
com.gs.fw.common.mithra.transaction.LocalTx Maven / Gradle / Ivy
/*
Copyright 2016 Goldman Sachs.
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 com.gs.fw.common.mithra.transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gs.fw.common.mithra.util.InternalList;
import javax.transaction.*;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.net.InetAddress;
import java.util.Arrays;
public class LocalTx implements Transaction
{
private static final Logger logger = LoggerFactory.getLogger(LocalTx.class.getName());
private static final TxStatus ACTIVE = new TxStatusActive();
private static final TxStatus MARKED_ROLLBACK = new TxStatusMarkedRollback();
private static final TxStatus ROLLING_BACK = new TxStatusRollingBack();
private static final TxStatus ROLLED_BACK = new TxStatusRolledBack();
private static final TxStatus PREPARING = new TxStatusPreparing();
private static final TxStatus COMMITTING = new TxStatusCommitting();
private static final TxStatus COMMITTED = new TxStatusCommitted();
private boolean timedout = false;
private boolean asyncCommitOrRollback = false;
private short currentBranch = 0;
private final InternalList resourceManagers = new InternalList(2);
private final InternalList activeXaResources = new InternalList(3);
private final InternalList synchronizations = new InternalList(2);
private LocalXid xid;
private TxStatus status = ACTIVE;
private Throwable rollbackCause;
private LocalTm localTm;
private long timeToDie;
public LocalTx(int timeout, LocalTm tm)
{
this.timeToDie = System.currentTimeMillis() + timeout * 1000;
this.xid = new LocalXid(this.currentBranch);
this.localTm = tm;
}
public boolean enlistResource(XAResource xaRes) throws IllegalStateException, RollbackException, SystemException
{
this.status.preEnlistCheck(this);
return this.status.enlistResource(this, xaRes);
}
public boolean isAsyncCommitOrRollback()
{
return asyncCommitOrRollback;
}
protected void setAsyncCommitOrRollback(boolean asyncCommitOrRollback)
{
this.asyncCommitOrRollback = asyncCommitOrRollback;
}
private TxGroup removeByCommitter(XAResource res)
{
for(int i=0;i> 32));
putInt(globalId, globalId.length - 8, (int) UNIQUE_ID);
putInt(globalId, globalId.length - 4, global);
putShort(branchId, 0, currentBranch);
}
public LocalXid(byte[] globalId, short currentBranch)
{
this.globalId = globalId;
putShort(branchId, 0, currentBranch);
}
static void putInt(byte[] b, int off, int val)
{
b[off + 3] = (byte) (val >>> 0);
b[off + 2] = (byte) (val >>> 8);
b[off + 1] = (byte) (val >>> 16);
b[off + 0] = (byte) (val >>> 24);
}
static void putShort(byte[] b, int off, short val)
{
b[off + 1] = (byte) (val >>> 0);
b[off + 0] = (byte) (val >>> 8);
}
public int getFormatId()
{
return 108;
}
public byte[] getBranchQualifier()
{
return this.branchId;
}
public byte[] getGlobalTransactionId()
{
return this.globalId;
}
public Xid makeNewBranch(short currentBranch)
{
return new LocalXid(this.globalId, currentBranch);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
{
int len = in.readByte();
this.globalId = new byte[len];
in.readFully(this.globalId);
len = in.readByte();
this.branchId = new byte[len];
in.readFully(this.branchId);
}
public void writeExternal(ObjectOutput out) throws IOException
{
out.writeByte(this.globalId.length);
out.write(this.globalId);
out.writeByte(this.branchId.length);
out.write(this.branchId);
}
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final LocalXid localXid = (LocalXid) o;
if (!Arrays.equals(branchId, localXid.branchId)) return false;
if (!Arrays.equals(globalId, localXid.globalId)) return false;
return true;
}
public int hashCode()
{
return (((int)globalId[globalId.length - 4]) << 24) |
(((int)globalId[globalId.length - 3]) << 16) |
(((int)globalId[globalId.length - 2]) << 8) |
(((int)globalId[globalId.length - 1]));
}
}
private abstract static class TxStatus
{
public abstract int getStatus(LocalTx tx);
public void preEnlistCheck(LocalTx localTx) throws RollbackException
{
throw new IllegalStateException("cannot enlist with status "+this.getClass().getName());
}
public boolean enlistResource(LocalTx tx, XAResource xaResource) throws SystemException
{
throw new IllegalStateException("cannot enlist with status "+this.getClass().getName());
}
public int preDelistCheck(LocalTx tx, int incomingFlag)
{
throw new IllegalStateException("cannot delist with status "+this.getClass().getName());
}
public void prePrepareCheck(LocalTx tx)
{
throw new IllegalStateException("cannot commit with status "+this.getClass().getName());
}
public abstract int getEndFlag();
public void beforeCompletion(LocalTx localTx)
{
// nothing to do
}
public void chooseStateForPrepare(LocalTx localTx) throws SystemException
{
throw new SystemException("unexpected state "+this.getClass().getName());
}
public void prepare(LocalTx localTx) throws SystemException
{
throw new SystemException("unexpected state "+this.getClass().getName());
}
public void commitOrPossiblyRollback(LocalTx tx) throws SystemException
{
throw new SystemException("unexpected commit "+this.getClass().getName());
}
public void afterCompletion(LocalTx tx) throws SystemException
{
throw new SystemException("unexpected afterCompletion "+this.getClass().getName());
}
public void registerSynchronization(LocalTx tx, Synchronization synchronization)
{
throw new IllegalStateException("can't register synchronization due to transaction state "+this.getClass().getName());
}
public void postCommitCheck(LocalTx localTx) throws RollbackException
{
throw new IllegalStateException("can't postCommitCheck due to transaction state "+this.getClass().getName());
}
public void setRollbackOnly(LocalTx tx)
{
throw new IllegalStateException("can't setRollbackOnly due to transaction state "+this.getClass().getName());
}
public void preRollbackCheck(LocalTx tx)
{
throw new IllegalStateException("can't preRollbackCheck due to transaction state "+this.getClass().getName());
}
public void chooseRollbackState(LocalTx tx)
{
throw new IllegalStateException("can't chooseRollbackState due to transaction state "+this.getClass().getName());
}
public void rollback(LocalTx tx) throws SystemException
{
throw new IllegalStateException("can't rollback due to transaction state "+this.getClass().getName());
}
}
private static class TxStatusActive extends TxStatus
{
@Override
public void registerSynchronization(LocalTx tx, Synchronization synchronization)
{
if (checkTimeout(tx))
{
tx.status.registerSynchronization(tx, synchronization);
}
else
{
tx.synchronizations.add(synchronization);
}
}
private boolean checkTimeout(LocalTx tx)
{
if (System.currentTimeMillis() > tx.timeToDie)
{
tx.status = MARKED_ROLLBACK;
tx.timedout = true;
return true;
}
return false;
}
@Override
public int getStatus(LocalTx tx)
{
if (checkTimeout(tx))
{
return Status.STATUS_MARKED_ROLLBACK;
}
else
{
return Status.STATUS_ACTIVE;
}
}
@Override
public void preEnlistCheck(LocalTx tx) throws RollbackException
{
if (checkTimeout(tx))
{
tx.status.preEnlistCheck(tx);
}
}
private boolean containsByCommitter(InternalList all, XAResource res)
{
for(int i=0;i
© 2015 - 2025 Weber Informatics LLC | Privacy Policy