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

org.wildfly.transaction.client.provider.remoting.Protocol Maven / Gradle / Ivy

/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2016 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * 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
 *
 *     http://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 org.wildfly.transaction.client.provider.remoting;

import static org.jboss.remoting3.util.StreamUtils.*;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

import javax.transaction.xa.Xid;

import org.wildfly.transaction.client.SimpleXid;

/**
 * @author David M. Lloyd
 */
class Protocol {
    public static final boolean SIGNED = true;
    public static final boolean UNSIGNED = false;

    public static final int VERSION_MIN = 0;
    public static final int VERSION_MAX = 0;

    // all msgs are initiated by the client
    // msg format
    // byte 0-1: inv ID
    // byte 2: M_ message type
    // byte 3...: P_ parameters

    // parameter format
    // byte 0: param ID
    // byte 1-x: length (packed integer)
    // byte x...: parameter payload of exactly length bytes

    // client -> server

    // Add capabilities; server only replies with acknowledged capabilities (may be empty) (error not raised on unrecognized)
    public static final int M_CAPABILITY    = 0x00; // P_*

    // unused                               = 0x01
    // Roll back the transaction with the given XID
    public static final int M_XA_ROLLBACK   = 0x02; // P_XID(gtid) [ P_SEC_CONTEXT ]
    // Prepare the transaction with the given XID
    public static final int M_XA_PREPARE    = 0x03; // P_XID(gtid) [ P_SEC_CONTEXT ]
    // Commit the transaction with the given XID
    public static final int M_XA_COMMIT     = 0x04; // P_XID(gtid) [ P_SEC_CONTEXT ] [ P_ONE_PHASE ]
    // Forget the transaction with the given XID
    public static final int M_XA_FORGET     = 0x05; // P_XID(gtid) [ P_SEC_CONTEXT ]
    // Execute before-completion for the transaction with the given XID
    public static final int M_XA_BEFORE     = 0x06; // P_XID(gtid) [ P_SEC_CONTEXT ]
    // Get a list of XIDs to recover
    public static final int M_XA_RECOVER    = 0x07; // [ P_SEC_CONTEXT ] [ P_PARENT_NAME ]
    // Mark the XA transaction as rollback-only; used if the resource was called with TMFAIL
    public static final int M_XA_RB_ONLY    = 0x08; // P_XID(gtid) [ P_SEC_CONTEXT ]
    // Unused
    // unused                               = 0x09;
    // TXN_CONTEXT is released (even for error)
    public static final int M_UT_COMMIT     = 0x0A; // P_TXN_CONTEXT [ P_SEC_CONTEXT ]
    // TXN_CONTEXT is released (even for error)
    public static final int M_UT_ROLLBACK   = 0x0B; // P_TXN_CONTEXT [ P_SEC_CONTEXT ]

    // server -> client

    public static final int M_RESP_CAPABILITY   = 0x00; // P_*

    // unused                                   = 0x11;
    public static final int M_RESP_XA_ROLLBACK  = 0x12; // [ P_XA_ERROR | P_SEC_EXC ]
    public static final int M_RESP_XA_PREPARE   = 0x13; // [ P_XA_RDONLY | P_XA_ERROR | P_SEC_EXC ]
    public static final int M_RESP_XA_COMMIT    = 0x14; // [ P_XA_ERROR | P_SEC_EXC ]
    public static final int M_RESP_XA_FORGET    = 0x15; // [ P_XA_ERROR | P_SEC_EXC ]
    public static final int M_RESP_XA_BEFORE    = 0x16; // [ P_XA_ERROR | P_SEC_EXC ]

    public static final int M_RESP_XA_RECOVER   = 0x17; // P_XID... | P_XA_ERROR | P_SEC_EXC

    public static final int M_RESP_XA_RB_ONLY   = 0x18; // [ P_XA_ERROR | P_SEC_EXC ]

    public static final int M_RESP_UT_COMMIT    = 0x1A; // [ P_UT_RB_EXC | P_UT_HME_EXC | P_UT_HRE_EXC | P_UT_SYS_EXC | P_SEC_EXC ]
    public static final int M_RESP_UT_ROLLBACK  = 0x1B; // [ P_UT_SYS_EXC | P_SEC_EXC ]

    public static final int M_RESP_PARAM_ERROR  = 0xFE; // empty (missing required or found unknown parameter)
    public static final int M_RESP_ERROR        = 0xFF; // empty (unknown request code)

    // parameters

    // unused                                 0x00
    public static final int P_XID           = 0x01; // body = XID
    public static final int P_ONE_PHASE     = 0x02; // len=0
    public static final int P_PARENT_NAME   = 0x03; // body = utf8
    // unused                                 0x04
    // unused                                 0x05
    // unused                                 0x06
    public static final int P_XA_RDONLY     = 0x07; // len=0

    // Exception types format:
    //  byte 0..3 = error code (XA and sys exceptions only)
    //  byte 4..n = org.wildfly.common.rpc.RemoteExceptionCause cause info (byte 0..n for non-XA/sysex)

    public static final int P_UT_RB_EXC     = 0x10; // RollbackException
    public static final int P_UT_HME_EXC    = 0x11; // HeuristicMixedException
    public static final int P_UT_HRE_EXC    = 0x12; // HeuristicRollbackException
    public static final int P_UT_SYS_EXC    = 0x13; // SystemException
    public static final int P_UT_IS_EXC     = 0x14; // IllegalStateException

    public static final int P_SEC_EXC       = 0x20; // SecurityException

    public static final int P_XA_ERROR      = 0x30; // body = packed-int (signed) XA error code

    public static final int P_VERSION_ERROR = 0x40; // additional capabilities must be negotiated (s -> c)

    public static final int P_SEC_CONTEXT   = 0xF0; // uint32 security context association ID
    public static final int P_TXN_CONTEXT   = 0xF1; // uint32 transaction context association ID

    public static void writeParam(int param, OutputStream os, int val, boolean signed) throws IOException {
        writeInt8(os, param);
        final int len;
        if (signed && val < 0) {
            // always write one sign byte if needed
            len = 32 - Integer.numberOfLeadingZeros(~val) + 8 >> 3;
        } else {
            len = 32 - Integer.numberOfLeadingZeros(val) + 7 >> 3;
        }
        writeInt8(os, len);
        switch (len) {
            case 4: writeInt8(os, val >> 24);
            case 3: writeInt8(os, val >> 16);
            case 2: writeInt8(os, val >> 8);
            case 1: writeInt8(os, val >> 0);
        }
    }

    public static void writeParam(int param, OutputStream os, byte[] bytes) throws IOException {
        writeInt8(os, param);
        if (bytes == null || bytes.length == 0) {
            writeInt8(os, 0);
        } else {
            writePackedUnsignedInt32(os, bytes.length);
            os.write(bytes);
        }
    }

    public static void writeParam(int param, OutputStream os, String str) throws IOException {
        if (str == null || str.isEmpty()) {
            writeParam(param, os);
        } else {
            writeParam(param, os, str.getBytes(StandardCharsets.UTF_8));
        }
    }

    public static void writeParam(int param, OutputStream os) throws IOException {
        writeInt8(os, param);
        writeInt8(os, 0);
    }

    public static void writeParam(int param, OutputStream os, Xid xid) throws IOException {
        if (xid == null) {
            writeParam(param, os);
            return;
        }
        final int formatId = xid.getFormatId();
        final byte[] gtid = xid.getGlobalTransactionId();
        final byte[] bq = xid.getBranchQualifier();
        if (gtid.length > Xid.MAXGTRIDSIZE || bq.length > Xid.MAXBQUALSIZE) {
            throw new IOException("Cannot write invalid XID");
        }
        final int len = gtid.length + bq.length + 5;
        //noinspection PointlessBooleanExpression,ConstantConditions
        assert Xid.MAXGTRIDSIZE <= 64 && Xid.MAXBQUALSIZE <= 64 && len < 256;
        // might be > 127
        writeInt8(os, param);
        writePackedUnsignedInt32(os, len);
        writeInt32BE(os, formatId);
        writeInt8(os, gtid.length);
        os.write(gtid);
        os.write(bq);
    }

    public static int readIntParam(InputStream is, int len) throws IOException {
        int t = 0;
        for (int i = 0; i < len; i ++) {
            t = t << 8 | readInt8(is) & 0xff;
        }
        return t;
    }

    public static String readStringParam(InputStream is, int len) throws IOException {
        byte[] b = new byte[len];
        readFully(is, b);
        return new String(b, StandardCharsets.UTF_8);
    }

    public static SimpleXid readXid(InputStream is, int len) throws IOException {
        final int formatId = readInt32BE(is);
        len -= 4;
        int gtidLen = readInt8(is);
        len --;
        if (len < gtidLen) {
            throw new EOFException();
        }
        final byte[] gtid = gtidLen == 0 ? SimpleXid.NO_BYTES : new byte[gtidLen];
        readFully(is, gtid);
        len -= gtidLen;
        final byte[] bq = len == 0 ? SimpleXid.NO_BYTES : new byte[len];
        readFully(is, bq);
        return new SimpleXid(formatId, gtid, bq);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy