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

uk.co.real_logic.artio.binary_entrypoint.BinaryEntryPointProxy Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021 Monotonic Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package uk.co.real_logic.artio.binary_entrypoint;

import b3.entrypoint.fixp.sbe.*;
import io.aeron.ExclusivePublication;
import io.aeron.logbuffer.BufferClaim;
import org.agrona.MutableDirectBuffer;
import org.agrona.concurrent.EpochNanoClock;
import org.agrona.concurrent.UnsafeBuffer;
import org.agrona.sbe.MessageEncoderFlyweight;
import uk.co.real_logic.artio.DebugLogger;
import uk.co.real_logic.artio.fixp.*;

import java.nio.ByteBuffer;
import java.util.function.Consumer;

import static uk.co.real_logic.artio.LogTag.FIXP_SESSION;
import static uk.co.real_logic.artio.fixp.SimpleOpenFramingHeader.BINARY_ENTRYPOINT_TYPE;
import static uk.co.real_logic.artio.fixp.SimpleOpenFramingHeader.SOFH_LENGTH;

public class BinaryEntryPointProxy extends AbstractFixPProxy
{
    public static final int BINARY_ENTRYPOINT_HEADER_LENGTH = SOFH_LENGTH + MessageHeaderEncoder.ENCODED_LENGTH;
    private static final int BINARY_ENTRYPOINT_MESSAGE_HEADER = ARTIO_HEADER_LENGTH + BINARY_ENTRYPOINT_HEADER_LENGTH;

    private static final int RETRANSMISSION_LEN = BINARY_ENTRYPOINT_HEADER_LENGTH +
        RetransmissionEncoder.BLOCK_LENGTH;
    private static final int SEQUENCE_LEN = BINARY_ENTRYPOINT_HEADER_LENGTH +
        SequenceEncoder.BLOCK_LENGTH;
    private static final int RETRANSMISSION_AND_SEQUENCE_LEN = ARTIO_HEADER_LENGTH + RETRANSMISSION_LEN + SEQUENCE_LEN;

    private static final int NEGOTIATE_REJECT_LENGTH = BINARY_ENTRYPOINT_HEADER_LENGTH +
        NegotiateRejectEncoder.BLOCK_LENGTH;
    private static final int ESTABLISH_REJECT_LENGTH = BINARY_ENTRYPOINT_HEADER_LENGTH +
        EstablishRejectEncoder.BLOCK_LENGTH;
    private static final int NEGOTIATE_LENGTH = BINARY_ENTRYPOINT_HEADER_LENGTH +
        NegotiateEncoder.BLOCK_LENGTH;
    private static final int ESTABLISH_LENGTH = BINARY_ENTRYPOINT_HEADER_LENGTH +
        EstablishEncoder.BLOCK_LENGTH;
    private static final int BUSINESS_REJECT_LENGTH = BusinessMessageRejectEncoder.BLOCK_LENGTH +
        BusinessMessageRejectEncoder.memoHeaderLength() + BusinessMessageRejectEncoder.textHeaderLength();

    private final MessageHeaderEncoder beMessageHeader = new MessageHeaderEncoder();
    private final NegotiateEncoder negotiate = new NegotiateEncoder();
    private final NegotiateResponseEncoder negotiateResponse = new NegotiateResponseEncoder();
    private final NegotiateRejectEncoder negotiateReject = new NegotiateRejectEncoder();
    private final EstablishEncoder establish = new EstablishEncoder();
    private final EstablishAckEncoder establishAck = new EstablishAckEncoder();
    private final EstablishRejectEncoder establishReject = new EstablishRejectEncoder();
    private final SequenceEncoder sequence = new SequenceEncoder();
    private final TerminateEncoder terminate = new TerminateEncoder();
    private final FinishedReceivingEncoder finishedReceiving = new FinishedReceivingEncoder();
    private final FinishedSendingEncoder finishedSending = new FinishedSendingEncoder();
    private final NotAppliedEncoder notApplied = new NotAppliedEncoder();
    private final RetransmissionEncoder retransmission = new RetransmissionEncoder();
    private final RetransmitRejectEncoder retransmitReject = new RetransmitRejectEncoder();
    private final BusinessMessageRejectEncoder businessMessageReject = new BusinessMessageRejectEncoder();

    private final Consumer negotiateResponseAppendTo = negotiateResponse::appendTo;
    private final Consumer negotiateRejectAppendTo = negotiateReject::appendTo;
    private final Consumer establishAckAppendTo = establishAck::appendTo;
    private final Consumer establishRejectAppendTo = establishReject::appendTo;
    private final Consumer terminateAppendTo = terminate::appendTo;
    private final Consumer sequenceAppendTo = sequence::appendTo;
    private final Consumer finishedReceivingAppendTo = finishedReceiving::appendTo;
    private final Consumer finishedSendingAppendTo = finishedSending::appendTo;
    private final Consumer notAppliedAppendTo = notApplied::appendTo;
    private final Consumer retransmissionAppendTo = retransmission::appendTo;
    private final Consumer retransmitRejectAppendTo = retransmitReject::appendTo;
    private final Consumer businessMessageRejectAppendTo = businessMessageReject::appendTo;

    private final UnsafeBuffer buffer = new UnsafeBuffer();
    private final EpochNanoClock clock;

    public BinaryEntryPointProxy(
        final BinaryEntryPointProtocol protocol,
        final FixPMessageDissector dissector,
        final long connectionId,
        final ExclusivePublication publication,
        final EpochNanoClock clock)
    {
        super(protocol, dissector, connectionId, publication);
        this.clock = clock;
    }

    public long sendSequence(final long sessionId, final long nextSentSeqNo)
    {
        final SequenceEncoder sequence = this.sequence;

        final long position = claimMessage(SequenceEncoder.BLOCK_LENGTH, sequence, clock.nanoTime());
        if (position < 0)
        {
            return position;
        }

        sequence
            .nextSeqNo(nextSentSeqNo);

        DebugLogger.logSbeDecoder(FIXP_SESSION, "< ", sequenceAppendTo);

        commit();

        return position;
    }

    public long sendNegotiateResponse(
        final long sessionID, final long sessionVerID, final long requestTimestamp, final long enteringFirm)
    {
        final NegotiateResponseEncoder negotiateResponse = this.negotiateResponse;

        final long position = claimMessage(NegotiateResponseEncoder.BLOCK_LENGTH, negotiateResponse, requestTimestamp);
        if (position < 0)
        {
            return position;
        }

        negotiateResponse
            .sessionID(sessionID)
            .sessionVerID(sessionVerID)
            .requestTimestamp().time(requestTimestamp);
        negotiateResponse
            .enteringFirm(enteringFirm);

        DebugLogger.logSbeDecoder(FIXP_SESSION, "< ", negotiateResponseAppendTo);

        commit();

        return position;
    }

    public long sendEstablishAck(
        final long sessionID,
        final long sessionVerID,
        final long requestTimestamp,
        final long keepAliveInterval,
        final long nextSeqNo,
        final long lastIncomingSeqNo)
    {
        final EstablishAckEncoder establishAck = this.establishAck;

        final long position = claimMessage(EstablishAckEncoder.BLOCK_LENGTH, establishAck, requestTimestamp);
        if (position < 0)
        {
            return position;
        }

        establishAck
            .sessionID(sessionID)
            .sessionVerID(sessionVerID)
            .requestTimestamp().time(requestTimestamp);
        establishAck.keepAliveInterval().time(keepAliveInterval);
        establishAck
            .nextSeqNo(nextSeqNo)
            .lastIncomingSeqNo(lastIncomingSeqNo);

        DebugLogger.logSbeDecoder(FIXP_SESSION, "< ", establishAckAppendTo);

        commit();

        return position;
    }

    public long sendNegotiateReject(
        final long sessionID,
        final long sessionVerID,
        final long requestTimestamp,
        final long enteringFirm,
        final NegotiationRejectCode negotiateRejectEncoder)
    {
        final NegotiateRejectEncoder negotiateReject = this.negotiateReject;

        final long position = claimMessage(NegotiateRejectEncoder.BLOCK_LENGTH, negotiateReject, requestTimestamp);
        if (position < 0)
        {
            return position;
        }

        negotiateReject
            .sessionID(sessionID)
            .sessionVerID(sessionVerID)
            .requestTimestamp().time(requestTimestamp);
        negotiateReject
            .enteringFirm(enteringFirm)
            .negotiationRejectCode(negotiateRejectEncoder);

        DebugLogger.logSbeDecoder(FIXP_SESSION, "< ", establishRejectAppendTo);

        commit();

        return position;
    }

    public long sendEstablishReject(
        final long sessionID,
        final long sessionVerID,
        final long requestTimestamp,
        final EstablishRejectCode establishmentRejectCode)
    {
        final EstablishRejectEncoder establishReject = this.establishReject;

        final long position = claimMessage(EstablishRejectEncoder.BLOCK_LENGTH, establishReject, requestTimestamp);
        if (position < 0)
        {
            return position;
        }

        establishReject
            .sessionID(sessionID)
            .sessionVerID(sessionVerID)
            .requestTimestamp().time(requestTimestamp);
        establishReject.establishmentRejectCode(establishmentRejectCode);

        DebugLogger.logSbeDecoder(FIXP_SESSION, "< ", establishRejectAppendTo);

        commit();

        return position;
    }

    public long sendTerminate(
        final long sessionId,
        final long sessionVerId,
        final TerminationCode terminationCode,
        final long timestampInNs)
    {
        final TerminateEncoder terminate = this.terminate;

        final long position = claimMessage(TerminateEncoder.BLOCK_LENGTH, terminate, timestampInNs);
        if (position < 0)
        {
            return position;
        }

        terminate
            .sessionID(sessionId)
            .sessionVerID(sessionVerId)
            .terminationCode(terminationCode);

        DebugLogger.logSbeDecoder(FIXP_SESSION, "< ", terminateAppendTo);

        commit();

        return position;
    }

    public long sendFinishedReceiving(final long sessionID, final long sessionVerId, final long timestampInNs)
    {
        final FinishedReceivingEncoder finishedReceiving = this.finishedReceiving;

        final long position = claimMessage(FinishedReceivingEncoder.BLOCK_LENGTH, finishedReceiving, timestampInNs);
        if (position < 0)
        {
            return position;
        }

        finishedReceiving
            .sessionID(sessionID)
            .sessionVerID(sessionVerId);

        DebugLogger.logSbeDecoder(FIXP_SESSION, "< ", finishedReceivingAppendTo);

        commit();

        return position;
    }

    public long sendFinishedSending(
        final long sessionId, final long sessionVerId, final long lastSeqNo, final long timestampInNs)
    {
        final FinishedSendingEncoder finishedSending = this.finishedSending;

        final long position = claimMessage(FinishedSendingEncoder.BLOCK_LENGTH, finishedSending, timestampInNs);
        if (position < 0)
        {
            return position;
        }

        finishedSending
            .sessionID(sessionId)
            .sessionVerID(sessionVerId)
            .lastSeqNo(lastSeqNo);

        DebugLogger.logSbeDecoder(FIXP_SESSION, "< ", finishedSendingAppendTo);

        commit();

        return position;
    }

    public long sendNotApplied(final long fromSeqNo, final long count, final long timestampInNs)
    {
        final NotAppliedEncoder notApplied = this.notApplied;

        final long position = claimMessage(NotAppliedEncoder.BLOCK_LENGTH, notApplied, timestampInNs);
        if (position < 0)
        {
            return position;
        }

        notApplied
            .fromSeqNo(fromSeqNo)
            .count(count);

        DebugLogger.logSbeDecoder(FIXP_SESSION, "< ", notAppliedAppendTo);

        commit();

        return position;
    }

    public long sendRetransmissionWithSequence(
        final long nextSeqNo,
        final long count,
        final long internalTimestampInNs,
        final long requestTimestampInNs,
        final long nextSentSeqNo)
    {
        final RetransmissionEncoder retransmission = this.retransmission;
        final SequenceEncoder sequence = this.sequence;
        final BufferClaim bufferClaim = this.bufferClaim;

        final long position = publication.tryClaim(RETRANSMISSION_AND_SEQUENCE_LEN, bufferClaim);
        if (position < 0)
        {
            return position;
        }

        final MutableDirectBuffer buffer = bufferClaim.buffer();
        int offset = bufferClaim.offset();

        fixPMessage
            .wrapAndApplyHeader(buffer, offset, messageHeader)
            .connection(connectionId)
            .sessionId(sessionId)
            .enqueueTime(internalTimestampInNs);

        offset += ARTIO_HEADER_LENGTH;

        SimpleOpenFramingHeader.writeSofh(buffer, offset, RETRANSMISSION_LEN, BINARY_ENTRYPOINT_TYPE);
        offset += SOFH_LENGTH;

        offset = applyHeader(retransmission, buffer, offset);

        retransmission
            .wrap(buffer, offset)
            .sessionID(sessionId)
            .requestTimestamp().time(requestTimestampInNs);
        retransmission
            .nextSeqNo(nextSeqNo)
            .count(count);

        offset += RetransmissionEncoder.BLOCK_LENGTH;

        SimpleOpenFramingHeader.writeSofh(buffer, offset, SEQUENCE_LEN, BINARY_ENTRYPOINT_TYPE);
        offset += SOFH_LENGTH;
        offset = applyHeader(sequence, buffer, offset);

        sequence
            .wrap(buffer, offset)
            .nextSeqNo(nextSentSeqNo);

        DebugLogger.logSbeDecoder(FIXP_SESSION, "< ", retransmissionAppendTo);
        DebugLogger.logSbeDecoder(FIXP_SESSION, "< ", sequenceAppendTo);

        commit();

        return position;
    }

    public long sendRetransmitReject(
        final RetransmitRejectCode retransmitRejectCode, final long timestampInNs, final long requestTimestampInNs)
    {
        final RetransmitRejectEncoder retransmitReject = this.retransmitReject;

        final long position = claimMessage(RetransmitRejectEncoder.BLOCK_LENGTH, retransmitReject, timestampInNs);
        if (position < 0)
        {
            return position;
        }

        retransmitReject
            .sessionID(sessionId)
            .requestTimestamp().time(requestTimestampInNs);
        retransmitReject.retransmitRejectCode(retransmitRejectCode);

        DebugLogger.logSbeDecoder(FIXP_SESSION, "< ", retransmitRejectAppendTo);

        commit();

        return position;
    }

    public long sendBusinessReject(
        final long refSeqNum, final MessageType refMsgType, final long rejectRefID, final long businessRejectReason)
    {
        final BusinessMessageRejectEncoder businessMessageReject = this.businessMessageReject;

        final long position = claimMessage(
            BUSINESS_REJECT_LENGTH, businessMessageReject, clock.nanoTime());
        if (position < 0)
        {
            return position;
        }

        businessMessageReject
            .refSeqNum(refSeqNum)
            .refMsgType(refMsgType)
            .businessRejectRefID(rejectRefID)
            .businessRejectReason(businessRejectReason);

        DebugLogger.logSbeDecoder(FIXP_SESSION, "< ", businessMessageRejectAppendTo);

        commit();

        return position;
    }

    public long claimMessage(
        final int messageLength,
        final MessageEncoderFlyweight message,
        final long timestampInNs)
    {
        return claimMessage(
            messageLength,
            message,
            timestampInNs,
            BINARY_ENTRYPOINT_MESSAGE_HEADER,
            BINARY_ENTRYPOINT_HEADER_LENGTH,
            BINARY_ENTRYPOINT_TYPE);
    }

    protected int applyHeader(
        final MessageEncoderFlyweight message, final MutableDirectBuffer buffer, final int offset)
    {
        beMessageHeader
            .wrap(buffer, offset)
            .blockLength(message.sbeBlockLength())
            .templateId(message.sbeTemplateId())
            .schemaId(message.sbeSchemaId())
            .version(message.sbeSchemaVersion());

        return offset + beMessageHeader.encodedLength();
    }

    public ByteBuffer encodeReject(
        final FixPContext fixPContext, final FixPFirstMessageResponse rejectReason, final Enum rejectCode)
    {
        final BinaryEntryPointContext identification = (BinaryEntryPointContext)fixPContext;

        final boolean isNegotiate;
        final NegotiationRejectCode negotiationRejectCode;
        final EstablishRejectCode establishRejectCode;
        switch (rejectReason)
        {
            case CREDENTIALS:
                isNegotiate = identification.fromNegotiate();
                if (rejectCode == null)
                {
                    negotiationRejectCode = NegotiationRejectCode.CREDENTIALS;
                    establishRejectCode = EstablishRejectCode.CREDENTIALS;
                }
                else if (isNegotiate)
                {
                    negotiationRejectCode = (NegotiationRejectCode)rejectCode;
                    establishRejectCode = null;
                }
                else
                {
                    establishRejectCode = (EstablishRejectCode)rejectCode;
                    negotiationRejectCode = null;
                }
                break;

            case NEGOTIATE_DUPLICATE_ID_BAD_VER:
            case NEGOTIATE_DUPLICATE_ID:
                isNegotiate = true;
                negotiationRejectCode = NegotiationRejectCode.ALREADY_NEGOTIATED;
                establishRejectCode = null;
                break;

            case NEGOTIATE_UNSPECIFIED:
                isNegotiate = true;
                negotiationRejectCode = NegotiationRejectCode.UNSPECIFIED;
                establishRejectCode = null;
                break;

            case ESTABLISH_UNNEGOTIATED:
            case ESTABLISH_DUPLICATE_ID:
                isNegotiate = false;
                negotiationRejectCode = null;
                establishRejectCode = EstablishRejectCode.UNNEGOTIATED;
                break;

            case VER_ID_ENDED:
                isNegotiate = identification.fromNegotiate();
                negotiationRejectCode = NegotiationRejectCode.NEGOTIATE_NOT_ALLOWED;
                establishRejectCode = EstablishRejectCode.UNNEGOTIATED;
                break;

            default:
                throw new IllegalArgumentException("Invalid reject reason: " + rejectReason);
        }

        final ByteBuffer byteBuffer;
        if (isNegotiate)
        {
            byteBuffer = ByteBuffer.allocate(NEGOTIATE_REJECT_LENGTH);
            buffer.wrap(byteBuffer);

            SimpleOpenFramingHeader.writeSofh(buffer, 0, NEGOTIATE_REJECT_LENGTH, BINARY_ENTRYPOINT_TYPE);
            negotiateReject
                .wrapAndApplyHeader(buffer, SOFH_LENGTH, beMessageHeader)
                .sessionID(identification.sessionID())
                .sessionVerID(identification.sessionVerID())
                .requestTimestamp().time(identification.requestTimestampInNs());
            negotiateReject
                .enteringFirm(identification.enteringFirm())
                .negotiationRejectCode(negotiationRejectCode);

            DebugLogger.logSbeDecoder(FIXP_SESSION, "< ", negotiateRejectAppendTo);
        }
        else
        {
            byteBuffer = ByteBuffer.allocate(ESTABLISH_REJECT_LENGTH);
            buffer.wrap(byteBuffer);

            SimpleOpenFramingHeader.writeSofh(buffer, 0, ESTABLISH_REJECT_LENGTH, BINARY_ENTRYPOINT_TYPE);
            establishReject
                .wrapAndApplyHeader(buffer, SOFH_LENGTH, beMessageHeader)
                .sessionID(identification.sessionID())
                .sessionVerID(identification.sessionVerID())
                .requestTimestamp().time(identification.requestTimestampInNs());
            establishReject
                .establishmentRejectCode(establishRejectCode);

            DebugLogger.logSbeDecoder(FIXP_SESSION, "< ", establishRejectAppendTo);
        }

        return byteBuffer;
    }

    public byte[] encodeFirstMessage(final FixPContext fixPContext)
    {
        final BinaryEntryPointContext context = (BinaryEntryPointContext)fixPContext;
        final byte[] bytes;
        if (context.fromNegotiate())
        {
            bytes = initBytes(NEGOTIATE_LENGTH);

            negotiate
                .wrapAndApplyHeader(buffer, SOFH_LENGTH, beMessageHeader)
                .sessionID(context.sessionID())
                .sessionVerID(context.sessionVerID())
                .timestamp().time(context.requestTimestampInNs());
            negotiate.enteringFirm(context.enteringFirm());
            negotiate.onbehalfFirm(NegotiateEncoder.onbehalfFirmNullValue());
        }
        else
        {
            bytes = initBytes(ESTABLISH_LENGTH);

            establish
                .wrapAndApplyHeader(buffer, SOFH_LENGTH, beMessageHeader)
                .sessionID(context.sessionID())
                .sessionVerID(context.sessionVerID())
                .timestamp().time(context.requestTimestampInNs());
            establish.keepAliveInterval().time(0);
            establish
                .nextSeqNo(EstablishEncoder.nextSeqNoNullValue())
                .cancelOnDisconnectType(CancelOnDisconnectType.DO_NOT_CANCEL_ON_DISCONNECT_OR_TERMINATE)
                .codTimeoutWindow().time(0);
        }

        return bytes;
    }

    private byte[] initBytes(final int length)
    {
        final byte[] bytes;
        bytes = new byte[length];
        buffer.wrap(bytes);
        SimpleOpenFramingHeader.writeSofh(buffer, 0, NEGOTIATE_LENGTH, BINARY_ENTRYPOINT_TYPE);
        return bytes;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy