/**
* 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.io.Serializable;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bytesoft.common.utils.ByteUtils;
import org.bytesoft.common.utils.CommonUtils;
import org.bytesoft.compensable.archive.CompensableArchive;
import org.bytesoft.compensable.archive.TransactionArchive;
import org.bytesoft.transaction.archive.XAResourceArchive;
import org.bytesoft.transaction.logging.ArchiveDeserializer;
import org.bytesoft.transaction.xa.TransactionXid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TransactionArchiveDeserializer extends org.bytesoft.bytejta.logging.deserializer.TransactionArchiveDeserializer
implements ArchiveDeserializer {
static final Logger logger = LoggerFactory.getLogger(TransactionArchiveDeserializer.class);
private ArchiveDeserializer resourceArchiveDeserializer;
private ArchiveDeserializer compensableArchiveDeserializer;
public byte[] serialize(TransactionXid xid, Object obj) {
TransactionArchive archive = (TransactionArchive) obj;
String propagatedBy = String.valueOf(archive.getPropagatedBy());
String[] address = propagatedBy.split("\\s*\\:\\s*");
byte[] hostByteArray = new byte[4];
byte[] portByteArray = new byte[2];
if (address.length == 2) {
String hostStr = address[0];
String portStr = address[1];
String[] hostArray = hostStr.split("\\s*\\.\\s*");
for (int i = 0; hostArray.length == 4 && i < hostArray.length; i++) {
try {
int value = Integer.valueOf(hostArray[i]);
hostByteArray[i] = (byte) (value - 128);
} catch (RuntimeException rex) {
logger.debug(rex.getMessage(), rex);
}
}
try {
short port = Short.valueOf(portStr);
byte[] byteArray = ByteUtils.shortToByteArray(port);
System.arraycopy(byteArray, 0, portByteArray, 0, 2);
} catch (RuntimeException rex) {
logger.debug(rex.getMessage(), rex);
}
}
List<CompensableArchive> nativeArchiveList = archive.getCompensableResourceList();
List<XAResourceArchive> remoteArchiveList = archive.getRemoteResources();
int nativeArchiveNumber = nativeArchiveList.size();
int remoteArchiveNumber = remoteArchiveList.size();
byte[] varByteArray = null;
if (archive.getVariables() == null) {
varByteArray = ByteUtils.shortToByteArray((short) 0);
} else {
try {
byte[] textByteArray = CommonUtils.serializeObject((Serializable) archive.getVariables());
byte[] sizeByteArray = ByteUtils.shortToByteArray((short) textByteArray.length);
varByteArray = new byte[sizeByteArray.length + textByteArray.length];
System.arraycopy(sizeByteArray, 0, varByteArray, 0, sizeByteArray.length);
System.arraycopy(textByteArray, 0, varByteArray, sizeByteArray.length, textByteArray.length);
} catch (Exception ex) {
logger.error("Error occurred while serializing variable: {}", archive.getVariables());
varByteArray = ByteUtils.shortToByteArray((short) 0);
}
}
int length = 6 + 4 + 2 + varByteArray.length + 2;
byte[][] nativeByteArray = new byte[nativeArchiveNumber][];
for (int i = 0; i < nativeArchiveNumber; i++) {
CompensableArchive compensableArchive = nativeArchiveList.get(i);
byte[] compensableByteArray = this.compensableArchiveDeserializer.serialize(xid, compensableArchive);
byte[] lengthByteArray = ByteUtils.shortToByteArray((short) compensableByteArray.length);
byte[] elementByteArray = new byte[compensableByteArray.length + 2];
System.arraycopy(lengthByteArray, 0, elementByteArray, 0, lengthByteArray.length);
System.arraycopy(compensableByteArray, 0, elementByteArray, 2, compensableByteArray.length);
nativeByteArray[i] = elementByteArray;
length = length + elementByteArray.length;
}
byte[][] remoteByteArray = new byte[remoteArchiveNumber][];
for (int i = 0; i < remoteArchiveNumber; i++) {
XAResourceArchive resourceArchive = remoteArchiveList.get(i);
byte[] resourceByteArray = this.resourceArchiveDeserializer.serialize(xid, resourceArchive);
byte[] lengthByteArray = ByteUtils.shortToByteArray((short) resourceByteArray.length);
byte[] elementByteArray = new byte[resourceByteArray.length + 2];
System.arraycopy(lengthByteArray, 0, elementByteArray, 0, lengthByteArray.length);
System.arraycopy(resourceByteArray, 0, elementByteArray, 2, resourceByteArray.length);
remoteByteArray[i] = elementByteArray;
length = length + elementByteArray.length;
}
int position = 0;
byte[] byteArray = new byte[length];
byteArray[position++] = (byte) archive.getStatus();
byteArray[position++] = (byte) archive.getVote();
byteArray[position++] = archive.isCoordinator() ? (byte) 0x1 : (byte) 0x0;
byteArray[position++] = archive.isPropagated() ? (byte) 0x1 : (byte) 0x0;
byteArray[position++] = archive.isCompensable() ? (byte) 0x1 : (byte) 0x0;
byteArray[position++] = (byte) archive.getCompensableStatus();
System.arraycopy(hostByteArray, 0, byteArray, position, 4);
position = position + 4;
System.arraycopy(portByteArray, 0, byteArray, position, 2);
position = position + 2;
System.arraycopy(varByteArray, 0, byteArray, position, varByteArray.length);
position = position + varByteArray.length;
byteArray[position++] = (byte) nativeArchiveNumber;
byteArray[position++] = (byte) remoteArchiveNumber;
for (int i = 0; i < nativeArchiveNumber; i++) {
byte[] elementByteArray = nativeByteArray[i];
System.arraycopy(elementByteArray, 0, byteArray, position, elementByteArray.length);
position = position + elementByteArray.length;
}
for (int i = 0; i < remoteArchiveNumber; i++) {
byte[] elementByteArray = remoteByteArray[i];
System.arraycopy(elementByteArray, 0, byteArray, position, elementByteArray.length);
position = position + elementByteArray.length;
}
return byteArray;
}
@SuppressWarnings("unchecked")
public Object deserialize(TransactionXid xid, byte[] array) {
ByteBuffer buffer = ByteBuffer.wrap(array);
TransactionArchive archive = new TransactionArchive();
archive.setXid(xid);
int status = buffer.get();
int vote = buffer.get();
int coordinatorValue = buffer.get();
int propagatedValue = buffer.get();
int compensableValue = buffer.get();
int compensableStatus = buffer.get();
archive.setStatus(status);
archive.setVote(vote);
archive.setCoordinator(coordinatorValue != 0);
archive.setPropagated(propagatedValue != 0);
archive.setCompensable(compensableValue != 0);
archive.setCompensableStatus(compensableStatus);
byte[] hostByteArray = new byte[4];
buffer.get(hostByteArray);
StringBuilder ber = new StringBuilder();
for (int i = 0; i < hostByteArray.length; i++) {
int value = hostByteArray[i] + 128;
if (i == 0) {
ber.append(value);
} else {
ber.append(".");
ber.append(value);
}
}
String host = ber.toString();
int port = buffer.getShort();
archive.setPropagatedBy(String.format("%s:%s", host, port));
short sizeOfVar = buffer.getShort();
if (sizeOfVar > 0) {
byte[] varByteArray = new byte[sizeOfVar];
buffer.get(varByteArray);
Map<String, Serializable> variables = null;
try {
variables = (Map<String, Serializable>) CommonUtils.deserializeObject(varByteArray);
} catch (Exception ex) {
variables = new HashMap<String, Serializable>();
logger.error("Error occurred while deserializing object: {}", varByteArray);
}
archive.setVariables(variables);
}
int nativeArchiveNumber = buffer.get();
int remoteArchiveNumber = buffer.get();
for (int i = 0; i < nativeArchiveNumber; i++) {
int length = buffer.getShort();
byte[] compensableByteArray = new byte[length];
buffer.get(compensableByteArray);
CompensableArchive compensableArchive = //
(CompensableArchive) this.compensableArchiveDeserializer.deserialize(xid, compensableByteArray);
archive.getCompensableResourceList().add(compensableArchive);
}
for (int i = 0; i < remoteArchiveNumber; i++) {
int length = buffer.getShort();
byte[] resourceByteArray = new byte[length];
buffer.get(resourceByteArray);
XAResourceArchive resourceArchive = //
(XAResourceArchive) this.resourceArchiveDeserializer.deserialize(xid, resourceByteArray);
archive.getRemoteResources().add(resourceArchive);
}
return archive;
}
public ArchiveDeserializer getResourceArchiveDeserializer() {
return resourceArchiveDeserializer;
}
public void setResourceArchiveDeserializer(ArchiveDeserializer resourceArchiveDeserializer) {
this.resourceArchiveDeserializer = resourceArchiveDeserializer;
}
public ArchiveDeserializer getCompensableArchiveDeserializer() {
return compensableArchiveDeserializer;
}
public void setCompensableArchiveDeserializer(ArchiveDeserializer compensableArchiveDeserializer) {
this.compensableArchiveDeserializer = compensableArchiveDeserializer;
}
}