org.refcodes.serial.ext.handshake.TransmissionMessage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of refcodes-serial-ext-handshake Show documentation
Show all versions of refcodes-serial-ext-handshake Show documentation
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/LICENSE-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 static org.refcodes.serial.SerialSugar.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.refcodes.exception.ExceptionAccessor.ExceptionProperty;
import org.refcodes.mixin.PayloadAccessor;
import org.refcodes.serial.AllocSegmentBody;
import org.refcodes.serial.AllocSegmentHead;
import org.refcodes.serial.AssertMagicBytesSegment;
import org.refcodes.serial.ComplexTypeSegment;
import org.refcodes.serial.PayloadSegment;
import org.refcodes.serial.Section;
import org.refcodes.serial.Segment;
import org.refcodes.serial.Sequence;
import org.refcodes.serial.SequenceNumberSegment;
import org.refcodes.serial.SequenceSection;
import org.refcodes.serial.SerialSchema;
import org.refcodes.serial.Transmission;
import org.refcodes.serial.TransmissionException;
import org.refcodes.struct.SimpleTypeMap;
import org.refcodes.struct.SimpleTypeMapImpl;
/**
* Implementation for a transmission {@link Message}.
*/
class TransmissionMessage implements HandshakeMessage, ExceptionProperty, PayloadAccessor, TransmissionTypeAccessor {
// /////////////////////////////////////////////////////////////////////////
// STATICS:
// /////////////////////////////////////////////////////////////////////////
private static final long serialVersionUID = 1L;
// /////////////////////////////////////////////////////////////////////////
// VARIABLES:
// /////////////////////////////////////////////////////////////////////////
private IOException _exception = null;
private boolean _hasAcknowledge = false;
private boolean _hasResponse = false;
private Segment _delegatee = null;
private Transmission _cargo;
private SequenceNumberSegment _sequenceNumberSegment;
private AssertMagicBytesSegment _assertMagicBytesSegment;
private HandshakeTransmissionMetrics _transmissionMetrics;
private Segment _responseSegment;
// /////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS:
// /////////////////////////////////////////////////////////////////////////
/**
* Instantiates a new {@link TransmissionMessage} with a plain
* {@link Sequence} as payload ready to receive an according cargo.
*
* @param aTransmissionType the transmission type
* @param aTransmissionMetrics The {@link HandshakeTransmissionMetrics} to
* use.
*/
public TransmissionMessage( TransmissionType aTransmissionType, HandshakeTransmissionMetrics aTransmissionMetrics ) {
if ( aTransmissionType == TransmissionType.PING ) {
toPingMessage( -1, aTransmissionType, aTransmissionMetrics );
}
else {
toTransmissionMessage( -1, aTransmissionType, (Sequence) null, aTransmissionMetrics );
}
}
/**
* Instantiates a new {@link TransmissionMessage} with the provided payload.
* It is up to the {@link TransmissionMessage} how to encode and (decode as
* of {@link #toPayload(Class)} the provided payload!
*
* @param The generic type of the payload to be carried by
* {@link TransmissionMessage}.
* @param aSequenceNumber The sequence number to be assigned to the
* {@link TransmissionMessage}.
* @param aTransmissionType The magic bytes identifying the transmission
* message.
* @param aPayload The payload to be carried by the
* {@link TransmissionMessage}.
* @param aTransmissionMetrics The {@link HandshakeTransmissionMetrics} to
* use.
*/
public TransmissionMessage( int aSequenceNumber, TransmissionType aTransmissionType, T aPayload, HandshakeTransmissionMetrics aTransmissionMetrics ) {
if ( aTransmissionType != TransmissionType.PING ) {
toTransmissionMessage( aSequenceNumber, aTransmissionType, new ComplexTypeSegment<>( aPayload, aTransmissionMetrics ), aTransmissionMetrics );
}
else {
throw new IllegalArgumentException( "This constructor must not(!) be invoked for a transmission type <" + TransmissionType.PING + ">!" );
}
}
/**
* Instantiates a new {@link TransmissionMessage} containing the given cargo
* {@link Segment}.
*
* @param aSequenceNumber The sequence number to be assigned to the
* {@link TransmissionMessage}.
* @param aTransmissionType The magic bytes identifying the transmission
* message.
* @param aRequestSegment The request {@link Segment} to be carried.
* @param aResponseSegment The {@link Segment} representing the response.
* @param aTransmissionMetrics The {@link HandshakeTransmissionMetrics} to
* use.
*/
public TransmissionMessage( int aSequenceNumber, TransmissionType aTransmissionType, Segment aRequestSegment, Segment aResponseSegment, HandshakeTransmissionMetrics aTransmissionMetrics ) {
if ( aTransmissionType != TransmissionType.PING ) {
toTransmissionMessage( aSequenceNumber, aTransmissionType, aRequestSegment, aTransmissionMetrics );
_responseSegment = aResponseSegment;
}
else {
throw new IllegalArgumentException( "This constructor must not(!) be invoked for a transmission type <" + TransmissionType.PING + ">!" );
}
}
/**
* Instantiates a new {@link TransmissionMessage} containing the given cargo
* {@link Segment}.
*
* @param aSequenceNumber The sequence number to be assigned to the
* {@link TransmissionMessage}.
* @param aTransmissionType The magic bytes identifying the transmission
* message.
* @param aTransmissionMetrics The {@link HandshakeTransmissionMetrics} to
* use.
*/
public TransmissionMessage( int aSequenceNumber, TransmissionType aTransmissionType, HandshakeTransmissionMetrics aTransmissionMetrics ) {
if ( aTransmissionType == TransmissionType.PING ) {
toPingMessage( aSequenceNumber, aTransmissionType, aTransmissionMetrics );
}
else {
throw new IllegalArgumentException( "This constructor must only be invoked for a transmission type <" + TransmissionType.PING + ">!" );
}
}
/**
* Instantiates a new {@link TransmissionMessage} containing the given cargo
* {@link Segment}.
*
* @param aSequenceNumber The sequence number to be assigned to the
* {@link TransmissionMessage}.
* @param aTransmissionType The {@link TransmissionType} and therewith the
* magic bytes identifying the transmission message.
* @param aCargoSegment The cargo {@link Segment} to be carried.
* @param aTransmissionMetrics The {@link HandshakeTransmissionMetrics} to
* use.
*/
public TransmissionMessage( int aSequenceNumber, TransmissionType aTransmissionType, Segment aCargoSegment, HandshakeTransmissionMetrics aTransmissionMetrics ) {
if ( aTransmissionType != TransmissionType.PING ) {
toTransmissionMessage( aSequenceNumber, aTransmissionType, aCargoSegment, aTransmissionMetrics );
}
else {
throw new IllegalArgumentException( "This constructor must not(!) be invoked for a transmission type <" + TransmissionType.PING + ">!" );
}
}
/**
* Instantiates a new {@link TransmissionMessage} containing the given cargo
* {@link Sequence}. The cargo {@link Sequence} is automatically labeled
* with the according cargo's length.
*
* @param aSequenceNumber The sequence number to be assigned to the
* {@link TransmissionMessage}.
* @param aTransmissionType The {@link TransmissionType} and therewith the
* magic bytes identifying the transmission message.
* @param aCargoSequence The cargo {@link Sequence} to be carried.
* @param aTransmissionMetrics The {@link HandshakeTransmissionMetrics} to
* use.
*/
public TransmissionMessage( int aSequenceNumber, TransmissionType aTransmissionType, Sequence aCargoSequence, HandshakeTransmissionMetrics aTransmissionMetrics ) {
if ( aTransmissionType != TransmissionType.PING ) {
toTransmissionMessage( aSequenceNumber, aTransmissionType, aCargoSequence, aTransmissionMetrics );
}
else {
throw new IllegalArgumentException( "This constructor must not(!) be invoked for a transmission type <" + TransmissionType.PING + ">!" );
}
}
// /////////////////////////////////////////////////////////////////////////
// METHODS:
// /////////////////////////////////////////////////////////////////////////
/**
* {@inheritDoc}
*/
@Override
public int getLength() {
return _delegatee.getLength();
}
/**
* {@inheritDoc}
*/
@Override
public Sequence toSequence() {
return _delegatee.toSequence();
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return getClass().getSimpleName() + " [segment=" + _delegatee + "]";
}
/**
* {@inheritDoc}
*/
@Override
public SimpleTypeMap toSimpleTypeMap() {
return _delegatee != null ? _delegatee.toSimpleTypeMap() : new SimpleTypeMapImpl();
}
/**
* {@inheritDoc}
*/
@Override
public void transmitTo( OutputStream aOutputStream, InputStream aReturnStream ) throws IOException {
_delegatee.transmitTo( aOutputStream, aReturnStream );
}
/**
* {@inheritDoc}
*/
@Override
public void reset() {
_assertMagicBytesSegment.reset();
_cargo.reset();
_delegatee.reset();
_exception = null;
_hasAcknowledge = false;
_hasResponse = false;
_responseSegment.reset();
_sequenceNumberSegment.reset();
}
/**
* {@inheritDoc}
*/
@Override
public SerialSchema toSchema() {
return _delegatee.toSchema();
}
/**
* {@inheritDoc}
*/
@Override
public int fromTransmission( Sequence aSequence, int aOffset ) throws TransmissionException {
return _delegatee.fromTransmission( aSequence, aOffset );
}
/**
* {@inheritDoc}
*/
@Override
public void receiveFrom( InputStream aInputStream, OutputStream aReturnStream ) throws IOException {
_delegatee.receiveFrom( aInputStream, aReturnStream );
}
/**
* {@inheritDoc}
*/
@Override
public int getSequenceNumber() {
if ( _sequenceNumberSegment != null ) {
return _sequenceNumberSegment.getValue() != null ? _sequenceNumberSegment.getValue().intValue() : -1;
}
throw new IllegalStateException( "A transmission segment of type <" + getTransmissionType() + "> does not have a sequence nummber!" );
}
/**
* {@inheritDoc}
*/
@Override
public byte[] getMagicBytes() {
return _assertMagicBytesSegment.getMagicBytes();
}
/**
* {@inheritDoc}
*/
@Override
public Transmission getPayload() {
return _cargo;
}
/**
* Initializes the provided {@link Segment} from this
* {@link TransmissionMessage}'s explicitly carried {@link Transmission}.
*
* @param The generic type of the {@link Segment} to be extracted.
*
* @param aPayloadSegment The preconfigured {@link Segment} to be
* initialized from this {@link TransmissionMessage}'s explicitly
* carried {@link Transmission}.
*
* @return The provided {@link Segment} initialized with this
* {@link TransmissionMessage}'s explicitly carried
* {@link Transmission}.
*
* @throws TransmissionException thrown in case the {@link Transmission}
* cannot be processed by the provided {@link Segment}.
*/
public SEGMENT toPayloadSegment( SEGMENT aPayloadSegment ) throws TransmissionException {
aPayloadSegment.fromTransmission( _cargo.toSequence() );
return aPayloadSegment;
}
/**
* Extracts the payload from this {@link TransmissionMessage}'s explicitly
* carried {@link Transmission} as of the provided preconfigured
* {@link PayloadSegment}.
*
* @param The generic type of the {@link PayloadSegment} from
* which to extract the payload.
* @param The generic type of the actual payload.
*
* @param aPayloadSegment The preconfigured {@link PayloadSegment} to use
* for extracting the payload from this {@link TransmissionMessage}
*
* @return The payload as of this {@link TransmissionMessage}'s encapsulated
* {@link Transmission}.
*
* @throws TransmissionException thrown in case the {@link Transmission}
* cannot be processed by the provided {@link PayloadSegment}.
*/
public , T> T toPayload( SEGMENT aPayloadSegment ) throws TransmissionException {
aPayloadSegment.fromTransmission( _cargo.toSequence() );
return aPayloadSegment.getPayload();
}
/**
* Decodes the payload to an instance of the given type. The payload must be
* either be passed to one of the constructors such as
* {@link #TransmissionMessage(Object)} or be encoded by a
* {@link ComplexTypeSegment} constructed with the same
* {@link HandshakeTransmissionMetrics} as this {@link TransmissionMessage}
* instance and passed to one of the other constructors such as
* {@link #TransmissionMessage(Segment )} or
* {@link #TransmissionMessage(Section)}.
*
* @param The generic type of the actual payload.
* @param aType The type of the payload for which to retrieve an instance
* created from the {@link TransmissionMessage} instance's cargo.
*
* @return The according instance created from the
* {@link TransmissionMessage} instance's cargo.
*
* @throws TransmissionException in case creating the given instance failed
* in case a given {@link Transmission} cannot be processed
* accordingly.
*/
public T toPayload( Class aType ) throws TransmissionException {
return toPayload( new ComplexTypeSegment<>( aType, _transmissionMetrics ) );
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ( ( _delegatee == null ) ? 0 : _delegatee.hashCode() );
return result;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals( Object obj ) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
final TransmissionMessage other = (TransmissionMessage) obj;
if ( _delegatee == null ) {
if ( other._delegatee != null ) {
return false;
}
}
else if ( !_delegatee.equals( other._delegatee ) ) {
return false;
}
return true;
}
/**
* Sets the acknowledgement status for to "acknowledged", e.g. the
* acknowledgement for this message is to be set.
*/
public void acknowledge() {
setAcknowledge( true );
}
/**
* Determines the acknowledgement status, e.g. whether there is already an
* acknowledgement for this message.
*
* @return The according acknowledgement status.
*/
public boolean hasAcknowledge() {
return _hasAcknowledge;
}
/**
* Sets the acknowledgement status for the message, e.g. whether there is
* already an acknowledgement for this message.
*
* @param hasAcknowledge the new acknowledge
*/
public void setAcknowledge( boolean hasAcknowledge ) {
_hasAcknowledge = hasAcknowledge;
}
/**
* Determines the response status, e.g. whether there is already a response
* for this message.
*
* @return The according response status.
*/
public boolean hasResponse() {
return _hasResponse;
}
/**
* Sets the response for this message.
*
* @param aResponse The {@link Sequence} representing the response.
*
* @throws TransmissionException in case the response {@link Sequence}
* cannot be deserialized by the response {@link Segment}.
*/
public void setResponse( Sequence aResponse ) throws TransmissionException {
_responseSegment.fromTransmission( aResponse );
_hasResponse = true;
}
/**
* {@inheritDoc}
*/
@Override
public IOException getException() {
return _exception;
}
/**
* {@inheritDoc}
*/
@Override
public void setException( IOException aException ) {
_exception = aException;
}
/**
* {@inheritDoc}
*/
@Override
public TransmissionType getTransmissionType() {
return _transmissionMetrics.toTransmissionType( _assertMagicBytesSegment.getMagicBytes() );
}
// /////////////////////////////////////////////////////////////////////////
// HELPER:
// /////////////////////////////////////////////////////////////////////////
private void toPingMessage( int aSequenceNumber, TransmissionType aTransmissionType, HandshakeTransmissionMetrics aTransmissionMetrics ) {
// @formatter:off
_delegatee = segmentComposite(
crcSegment(
segmentComposite(
_assertMagicBytesSegment = assertMagicBytesSegment( aTransmissionMetrics.toMagicBytes( aTransmissionType ), aTransmissionMetrics ),
_sequenceNumberSegment = sequenceNumberSegment( aSequenceNumber, aTransmissionMetrics )
),
aTransmissionMetrics
)
);
// @formatter:on
_transmissionMetrics = aTransmissionMetrics;
}
private void toTransmissionMessage( int aSequenceNumber, TransmissionType aTransmissionType, Segment aCargoSegment, HandshakeTransmissionMetrics aTransmissionMetrics ) {
// @formatter:off
_delegatee = segmentComposite(
crcSegment(
segmentComposite(
_assertMagicBytesSegment = assertMagicBytesSegment( aTransmissionMetrics.toMagicBytes( aTransmissionType ), aTransmissionMetrics ),
segmentLength( aCargoSegment, aTransmissionMetrics ),
_sequenceNumberSegment = sequenceNumberSegment( aSequenceNumber, aTransmissionMetrics )
),
aTransmissionMetrics
),
crcSegment( aCargoSegment, aTransmissionMetrics )
);
// @formatter:on
_cargo = aCargoSegment;
_transmissionMetrics = aTransmissionMetrics;
}
private void toTransmissionMessage( int aSequenceNumber, TransmissionType aTransmissionType, Sequence aCargoSequence, HandshakeTransmissionMetrics aTransmissionMetrics ) {
aTransmissionMetrics = aTransmissionMetrics != null ? aTransmissionMetrics : new HandshakeTransmissionMetrics();
final SequenceSection theSequenceSection = aCargoSequence != null ? sequenceSection( aCargoSequence ) : sequenceSection();
final AllocSegmentBody theAllocBody = allocSegmentBody( theSequenceSection );
final AllocSegmentHead theAllocHead = allocSegmentHead( theAllocBody, aTransmissionMetrics );
// @formatter:off
_delegatee = segmentComposite(
crcSegment(
segmentComposite(
_assertMagicBytesSegment = assertMagicBytesSegment( aTransmissionMetrics.toMagicBytes( aTransmissionType ), aTransmissionMetrics),
theAllocHead,
_sequenceNumberSegment = sequenceNumberSegment( aSequenceNumber, aTransmissionMetrics )
),
aTransmissionMetrics
),
crcSegment(
theAllocBody, aTransmissionMetrics
)
);
// @formatter:on
_cargo = theAllocBody;
_transmissionMetrics = aTransmissionMetrics;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy