/**
* Copyright 2014-2016 yangming.liu<bytefox@126.com>.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, see <http://www.gnu.org/licenses/>.
*/
package org.bytesoft.bytetcc.logging.deserializer;
import java.util.Arrays;
import javax.transaction.xa.Xid;
import org.bytesoft.common.utils.ByteUtils;
import org.bytesoft.common.utils.CommonUtils;
import org.bytesoft.compensable.CompensableBeanFactory;
import org.bytesoft.compensable.CompensableInvocation;
import org.bytesoft.compensable.archive.CompensableArchive;
import org.bytesoft.compensable.aware.CompensableBeanFactoryAware;
import org.bytesoft.transaction.logging.ArchiveDeserializer;
import org.bytesoft.transaction.xa.TransactionXid;
import org.bytesoft.transaction.xa.XidFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CompensableArchiveDeserializer implements ArchiveDeserializer, CompensableBeanFactoryAware {
static final Logger logger = LoggerFactory.getLogger(CompensableArchiveDeserializer.class);
static final int LENGTH_OF_XID = XidFactory.GLOBAL_TRANSACTION_LENGTH + XidFactory.BRANCH_QUALIFIER_LENGTH;
private CompensableBeanFactory beanFactory;
public byte[] serialize(TransactionXid xid, Object obj) {
CompensableArchive archive = (CompensableArchive) obj;
CompensableInvocation compensable = archive.getCompensable();
byte[] byteArray = new byte[0];
try {
byteArray = CommonUtils.serializeObject(compensable);
} catch (Exception ex) {
if (compensable == null) {
logger.error("Error occurred while serializing compensable: {}", compensable);
} else {
logger.error("Error occurred while serializing args: {}", compensable.getArgs());
}
}
String transactionResourceKey = archive.getTransactionResourceKey();
String compensableResourceKey = archive.getCompensableResourceKey();
byte[] transactionResourceKeyByteArray = transactionResourceKey == null ? new byte[0]
: transactionResourceKey.getBytes();
byte[] compensableResourceKeyByteArray = compensableResourceKey == null ? new byte[0]
: compensableResourceKey.getBytes();
byte[] resultArray = new byte[XidFactory.GLOBAL_TRANSACTION_LENGTH + XidFactory.BRANCH_QUALIFIER_LENGTH
+ LENGTH_OF_XID * 2 + 1 //
+ 2 + transactionResourceKeyByteArray.length //
+ 2 + compensableResourceKeyByteArray.length //
+ byteArray.length];
Xid identifier = archive.getIdentifier();
byte[] globalByteArray = identifier.getGlobalTransactionId();
byte[] branchByteArray = identifier.getBranchQualifier();
System.arraycopy(globalByteArray, 0, resultArray, 0, XidFactory.GLOBAL_TRANSACTION_LENGTH);
System.arraycopy(branchByteArray, 0, resultArray, XidFactory.GLOBAL_TRANSACTION_LENGTH,
XidFactory.BRANCH_QUALIFIER_LENGTH);
Xid transactionXid = archive.getTransactionXid();
Xid compensableXid = archive.getCompensableXid();
byte[] transactionGlobalTransactionId = null;
byte[] transactionBranchQualifier = null;
byte[] compensableGlobalTransactionId = null;
byte[] compensableBranchQualifier = null;
if (transactionXid == null) {
transactionGlobalTransactionId = new byte[XidFactory.GLOBAL_TRANSACTION_LENGTH];
transactionBranchQualifier = new byte[XidFactory.BRANCH_QUALIFIER_LENGTH];
} else {
transactionGlobalTransactionId = transactionXid.getGlobalTransactionId();
transactionBranchQualifier = transactionXid.getBranchQualifier();
}
System.arraycopy(transactionGlobalTransactionId, 0, resultArray, LENGTH_OF_XID, XidFactory.GLOBAL_TRANSACTION_LENGTH);
System.arraycopy(transactionBranchQualifier, 0, resultArray, LENGTH_OF_XID + XidFactory.GLOBAL_TRANSACTION_LENGTH,
XidFactory.BRANCH_QUALIFIER_LENGTH);
if (compensableXid == null) {
compensableGlobalTransactionId = new byte[XidFactory.GLOBAL_TRANSACTION_LENGTH];
compensableBranchQualifier = new byte[XidFactory.BRANCH_QUALIFIER_LENGTH];
} else {
compensableGlobalTransactionId = compensableXid.getGlobalTransactionId();
compensableBranchQualifier = compensableXid.getBranchQualifier();
}
System.arraycopy(compensableGlobalTransactionId, 0, resultArray, LENGTH_OF_XID * 2,
XidFactory.GLOBAL_TRANSACTION_LENGTH);
System.arraycopy(compensableBranchQualifier, 0, resultArray, LENGTH_OF_XID * 2 + XidFactory.GLOBAL_TRANSACTION_LENGTH,
XidFactory.BRANCH_QUALIFIER_LENGTH);
int value = archive.isCoordinator() ? 0x1 : 0x0;
int triedValue = archive.isTried() ? 0x1 : 0x0;
int confirmValue = archive.isConfirmed() ? 0x1 : 0x0;
int cancelValue = archive.isCancelled() ? 0x1 : 0x0;
// int mixedValue = archive.isTxMixed() ? 0x1 : 0x0;
value = value | (triedValue << 1);
value = value | (confirmValue << 2);
value = value | (cancelValue << 3);
// value = value | (mixedValue << 4);
resultArray[LENGTH_OF_XID * 3] = (byte) value;
byte[] lengthOfTransactionResourceKey = ByteUtils.shortToByteArray((short) transactionResourceKeyByteArray.length);
byte[] lengthOfCompensableResourceKey = ByteUtils.shortToByteArray((short) compensableResourceKeyByteArray.length);
int index = LENGTH_OF_XID * 3 + 1;
System.arraycopy(lengthOfTransactionResourceKey, 0, resultArray, index, lengthOfTransactionResourceKey.length);
index += lengthOfTransactionResourceKey.length;
System.arraycopy(transactionResourceKeyByteArray, 0, resultArray, index, transactionResourceKeyByteArray.length);
index += transactionResourceKeyByteArray.length;
System.arraycopy(lengthOfCompensableResourceKey, 0, resultArray, index, lengthOfCompensableResourceKey.length);
index += lengthOfCompensableResourceKey.length;
System.arraycopy(compensableResourceKeyByteArray, 0, resultArray, index, compensableResourceKeyByteArray.length);
index += compensableResourceKeyByteArray.length;
System.arraycopy(byteArray, 0, resultArray, index, byteArray.length);
return resultArray;
}
public Object deserialize(TransactionXid xid, byte[] array) {
byte[] globalByteArray = new byte[XidFactory.GLOBAL_TRANSACTION_LENGTH];
byte[] branchByteArray = new byte[XidFactory.BRANCH_QUALIFIER_LENGTH];
System.arraycopy(array, 0, globalByteArray, 0, globalByteArray.length);
System.arraycopy(array, XidFactory.GLOBAL_TRANSACTION_LENGTH, branchByteArray, 0, branchByteArray.length);
byte[] transactionGlobalTransactionId = new byte[XidFactory.GLOBAL_TRANSACTION_LENGTH];
byte[] transactionBranchQualifier = new byte[XidFactory.BRANCH_QUALIFIER_LENGTH];
byte[] compensableGlobalTransactionId = new byte[XidFactory.GLOBAL_TRANSACTION_LENGTH];
byte[] compensableBranchQualifier = new byte[XidFactory.BRANCH_QUALIFIER_LENGTH];
System.arraycopy(array, LENGTH_OF_XID, transactionGlobalTransactionId, 0, transactionGlobalTransactionId.length);
System.arraycopy(array, LENGTH_OF_XID + XidFactory.GLOBAL_TRANSACTION_LENGTH, transactionBranchQualifier, 0,
transactionBranchQualifier.length);
System.arraycopy(array, LENGTH_OF_XID * 2, compensableGlobalTransactionId, 0, compensableGlobalTransactionId.length);
System.arraycopy(array, LENGTH_OF_XID * 2 + XidFactory.GLOBAL_TRANSACTION_LENGTH, compensableBranchQualifier, 0,
compensableBranchQualifier.length);
int value = array[LENGTH_OF_XID * 3];
boolean coordinator = (value & 0x1) == 0x1;
boolean tried = ((value >>> 1) & 0x1) == 0x1;
boolean confirmed = ((value >>> 2) & 0x1) == 0x1;
boolean cancelled = ((value >>> 3) & 0x1) == 0x1;
// boolean mixed = ((value >>> 4) & 0x1) == 0x1;
int index = LENGTH_OF_XID * 3 + 1;
byte[] lengthOfTransactionResourceKey = new byte[2];
System.arraycopy(array, index, lengthOfTransactionResourceKey, 0, lengthOfTransactionResourceKey.length);
index += lengthOfTransactionResourceKey.length;
short transactionResourceKeySize = ByteUtils.byteArrayToShort(lengthOfTransactionResourceKey);
byte[] transactionResourceKeyByteArray = new byte[transactionResourceKeySize];
System.arraycopy(array, index, transactionResourceKeyByteArray, 0, transactionResourceKeyByteArray.length);
index += transactionResourceKeyByteArray.length;
byte[] lengthOfCompensableResourceKey = new byte[2];
System.arraycopy(array, index, lengthOfCompensableResourceKey, 0, lengthOfCompensableResourceKey.length);
index += lengthOfCompensableResourceKey.length;
short compensableResourceKeySize = ByteUtils.byteArrayToShort(lengthOfCompensableResourceKey);
byte[] compensableResourceKeyByteArray = new byte[compensableResourceKeySize];
System.arraycopy(array, index, compensableResourceKeyByteArray, 0, compensableResourceKeyByteArray.length);
index += compensableResourceKeyByteArray.length;
String transactionResourceKey = transactionResourceKeyByteArray.length == 0 ? null
: new String(transactionResourceKeyByteArray);
String compensableResourceKey = compensableResourceKeyByteArray.length == 0 ? null
: new String(compensableResourceKeyByteArray);
int usedSize = LENGTH_OF_XID * 3 + 1 + 2 + transactionResourceKeySize + 2 + compensableResourceKeySize;
byte[] byteArray = new byte[array.length - usedSize];
System.arraycopy(array, index, byteArray, 0, byteArray.length);
CompensableInvocation compensable = null;
try {
compensable = (CompensableInvocation) CommonUtils.deserializeObject(byteArray);
} catch (Exception ex) {
logger.error("Error occurred while deserializing object: {}", byteArray);
}
XidFactory xidFactory = this.beanFactory.getTransactionXidFactory();
Xid transactionXid = null;
Xid compensableXid = null;
if (Arrays.equals(transactionGlobalTransactionId, new byte[XidFactory.GLOBAL_TRANSACTION_LENGTH]) == false) {
TransactionXid transactionGlobalXid = xidFactory.createGlobalXid(transactionGlobalTransactionId);
transactionXid = xidFactory.createBranchXid(transactionGlobalXid, transactionBranchQualifier);
}
if (Arrays.equals(compensableGlobalTransactionId, new byte[XidFactory.GLOBAL_TRANSACTION_LENGTH]) == false) {
TransactionXid compensableGlobalXid = xidFactory.createGlobalXid(compensableGlobalTransactionId);
compensableXid = xidFactory.createBranchXid(compensableGlobalXid, compensableBranchQualifier);
}
TransactionXid globalXid = xidFactory.createGlobalXid(globalByteArray);
TransactionXid identifier = xidFactory.createBranchXid(globalXid, branchByteArray);
CompensableArchive archive = new CompensableArchive();
archive.setIdentifier(identifier);
archive.setCoordinator(coordinator);
archive.setTried(tried);
archive.setConfirmed(confirmed);
archive.setCancelled(cancelled);
// archive.setTxMixed(mixed);
archive.setCompensable(compensable);
archive.setTransactionXid(transactionXid);
archive.setCompensableXid(compensableXid);
archive.setTransactionResourceKey(transactionResourceKey);
archive.setCompensableResourceKey(compensableResourceKey);
return archive;
}
public void setBeanFactory(CompensableBeanFactory tbf) {
this.beanFactory = tbf;
}
}