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

uk.co.real_logic.artio.binary_entrypoint.BinaryEntryPointContext 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.EstablishRejectCode;
import b3.entrypoint.fixp.sbe.NegotiationRejectCode;
import uk.co.real_logic.artio.fixp.FixPContext;
import uk.co.real_logic.artio.fixp.FixPFirstMessageResponse;
import uk.co.real_logic.artio.fixp.InternalFixPContext;
import uk.co.real_logic.artio.messages.FixPProtocolType;

import static uk.co.real_logic.artio.binary_entrypoint.BinaryEntryPointProtocol.unsupported;
import static uk.co.real_logic.artio.dictionary.generation.CodecUtil.MISSING_INT;
import static uk.co.real_logic.artio.fixp.AbstractFixPSequenceExtractor.NEXT_SESSION_VERSION_ID;
import static uk.co.real_logic.artio.fixp.FixPFirstMessageResponse.*;

public class BinaryEntryPointContext implements InternalFixPContext
{

    public static final long ANY_FIRM_ID = -1;

    // persisted state
    private final long sessionID;
    private final long sessionVerID;
    private final long requestTimestampInNs;
    private final long enteringFirm;
    private boolean ended;

    // Not persisted
    private final boolean fromNegotiate;
    private final String credentials;
    private final String clientIP;
    private final String clientAppName;
    private final String clientAppVersion;
    private final BinaryEntryPointKey key;
    private boolean hasUnsentMessagesAtNegotiate;

    private int offset = MISSING_INT;

    public BinaryEntryPointContext(
        final long sessionID,
        final long sessionVerID,
        final long timestampInNs,
        final long enteringFirm,
        final boolean fromNegotiate,
        final String credentials,
        final String clientIP,
        final String clientAppName,
        final String clientAppVersion)
    {
        this.sessionID = sessionID;
        this.sessionVerID = sessionVerID;
        this.requestTimestampInNs = timestampInNs;
        this.enteringFirm = enteringFirm;
        this.fromNegotiate = fromNegotiate;
        this.credentials = credentials;
        this.clientIP = clientIP;
        this.clientAppName = clientAppName;
        this.clientAppVersion = clientAppVersion;

        ended = false;
        hasUnsentMessagesAtNegotiate = sessionVerID == NEXT_SESSION_VERSION_ID;
        key = new BinaryEntryPointKey(sessionID);
    }

    public static BinaryEntryPointContext forNextSessionVerID(
        final long sessionId, final long nanoTime)
    {
        return new BinaryEntryPointContext(
            sessionId,
            BinaryEntryPointConnection.NEXT_SESSION_VERSION_ID,
            nanoTime,
            ANY_FIRM_ID,
            true,
            "",
            "",
            "",
            "");
    }

    public long sessionID()
    {
        return sessionID;
    }

    public long sessionVerID()
    {
        return sessionVerID;
    }

    public long requestTimestampInNs()
    {
        return requestTimestampInNs;
    }

    public long enteringFirm()
    {
        return enteringFirm;
    }

    public boolean fromNegotiate()
    {
        return fromNegotiate;
    }

    /**
     * {@inheritDoc}
     */
    public BinaryEntryPointKey key()
    {
        return key;
    }

    /**
     * {@inheritDoc}
     */
    public FixPFirstMessageResponse checkAccept(final FixPContext fixPContext, final boolean ignoreFromNegotiate)
    {
        if (fixPContext == null)
        {
            if (ignoreFromNegotiate)
            {
                return OK;
            }
            else
            {
                return checkFirstConnect();
            }
        }

        validateType(fixPContext);

        final BinaryEntryPointContext oldContext = (BinaryEntryPointContext)fixPContext;
        if (sessionID != oldContext.sessionID)
        {
            throw new IllegalArgumentException("Unable to compare: " + sessionID + " to " + oldContext.sessionID);
        }

        offset = oldContext.offset();

        if (ignoreFromNegotiate)
        {
            // cannot re-started an ended session
            return oldContext.ended ? VER_ID_ENDED : OK;
        }
        else
        {
            // negotiations should increment the session ver id
            final long oldSessionVerID = oldContext.sessionVerID;
            if (fromNegotiate)
            {
                if (sessionVerID > oldSessionVerID)
                {
                    // We only copy this once as they will be sent on the next logon and then become part of that
                    // session version id form that point onwards
                    hasUnsentMessagesAtNegotiate = oldSessionVerID == NEXT_SESSION_VERSION_ID;
                    return OK;
                }

                return NEGOTIATE_DUPLICATE_ID;
            }
            // establish messages shouldn't
            else
            {
                // Continue the same sequence
                if (oldSessionVerID == sessionVerID)
                {
                    // cannot re-restablish an ended session
                    return oldContext.ended ? VER_ID_ENDED : OK;
                }

                return ESTABLISH_UNNEGOTIATED;
            }
        }
    }

    private void validateType(final FixPContext fixPContext)
    {
        if (!(fixPContext instanceof BinaryEntryPointContext))
        {
            throw new IllegalArgumentException("Unable to compare protocol: " + this + " to " + fixPContext);
        }
    }

    public int compareVersion(final FixPContext fixPContext)
    {
        validateType(fixPContext);

        final BinaryEntryPointContext oldContext = (BinaryEntryPointContext)fixPContext;
        return Long.compare(sessionVerID, oldContext.sessionVerID);
    }

    /**
     * {@inheritDoc}
     */
    public void initiatorReconnect(final boolean reestablishConnection)
    {
        unsupported();
    }

    public boolean onInitiatorNegotiateResponse()
    {
        return unsupported();
    }

    public void onInitiatorDisconnect()
    {
        unsupported();
    }

    /**
     * {@inheritDoc}
     */
    public FixPProtocolType protocolType()
    {
        return FixPProtocolType.BINARY_ENTRYPOINT;
    }

    /**
     * {@inheritDoc}
     */
    public void onEndSequence()
    {
        ended = true;
    }

    public String credentials()
    {
        return credentials;
    }

    /**
     * If this context was created from a Negotiate message then this method return the clientIP field. If the context
     * was created from an Establish message or {@link #forNextSessionVerID(long, long)} then it will be
     * "".
     *
     * @return the negotiate message's clientIP field or "".
     */
    public String clientIP()
    {
        return clientIP;
    }

    /**
     * If this context was created from a Negotiate message then this method return the clientAppName field. If the
     * context was created from an Establish message or {@link #forNextSessionVerID(long, long)} then it will be
     * "".
     *
     * @return the negotiate message's clientAppName field or "".
     */
    public String clientAppName()
    {
        return clientAppName;
    }

    /**
     * If this context was created from a Negotiate message then this method return the clientAppVersion field. If the
     * context was created from an Establish message or {@link #forNextSessionVerID(long, long)} then it will be
     * "".
     *
     * @return the negotiate message's clientAppVersion field or "".
     */
    public String clientAppVersion()
    {
        return clientAppVersion;
    }

    public FixPFirstMessageResponse checkFirstConnect()
    {
        if (!fromNegotiate)
        {
            return ESTABLISH_UNNEGOTIATED;
        }

        return OK;
    }

    void offset(final int offset)
    {
        this.offset = offset;
    }

    int offset()
    {
        return offset;
    }

    boolean ended()
    {
        return ended;
    }

    void ended(final boolean ended)
    {
        this.ended = ended;
    }

    public long surrogateSessionId()
    {
        return sessionID;
    }

    public boolean equals(final Object o)
    {
        if (this == o)
        {
            return true;
        }
        if (o == null || getClass() != o.getClass())
        {
            return false;
        }

        final BinaryEntryPointContext that = (BinaryEntryPointContext)o;

        if (sessionID != that.sessionID)
        {
            return false;
        }
        if (sessionVerID != that.sessionVerID)
        {
            return false;
        }

        return requestTimestampInNs == that.requestTimestampInNs;
    }

    public int hashCode()
    {
        int result = (int)(sessionID ^ (sessionID >>> 32));
        result = 31 * result + (int)(sessionVerID ^ (sessionVerID >>> 32));
        result = 31 * result + (int)(requestTimestampInNs ^ (requestTimestampInNs >>> 32));
        return result;
    }

    public String toString()
    {
        return "BinaryEntryPointContext{" +
            "sessionID=" + sessionID +
            ", sessionVerID=" + sessionVerID +
            ", requestTimestampInNs=" + requestTimestampInNs +
            ", enteringFirm=" + enteringFirm +
            ", fromNegotiate=" + fromNegotiate +
            ", credentials=" + credentials +
            ", clientIP=" + clientIP +
            ", clientAppName=" + clientAppName +
            ", clientAppVersion=" + clientAppVersion +
            '}';
    }

    public boolean hasUnsentMessagesAtNegotiate()
    {
        return hasUnsentMessagesAtNegotiate;
    }

    public void validate(final Enum rejectCode)
    {
        if (fromNegotiate())
        {
            validate(rejectCode, NegotiationRejectCode.class);
        }
        else
        {
            validate(rejectCode, EstablishRejectCode.class);
        }
    }

    private void validate(final Enum rejectCode, final Class expectedClass)
    {
        if (rejectCode.getClass() != expectedClass)
        {
            throw new IllegalArgumentException(
                "Invalid reject code used: " + rejectCode + " should be of type: " + expectedClass);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy