org.wildfly.transaction.client.provider.remoting.Protocol Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including
all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and
JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
/*
* 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);
}
}