Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.seasar.extension.jta.TransactionImpl Maven / Gradle / Ivy
/*
* Copyright 2004-2015 the Seasar Foundation and the Others.
*
* 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.seasar.extension.jta;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import org.seasar.extension.jta.xa.XidImpl;
import org.seasar.framework.exception.SIllegalStateException;
import org.seasar.framework.exception.SRollbackException;
import org.seasar.framework.exception.SSystemException;
import org.seasar.framework.log.Logger;
import org.seasar.framework.util.SLinkedList;
import jakarta.transaction.HeuristicMixedException;
import jakarta.transaction.HeuristicRollbackException;
import jakarta.transaction.NotSupportedException;
import jakarta.transaction.RollbackException;
import jakarta.transaction.Status;
import jakarta.transaction.Synchronization;
import jakarta.transaction.SystemException;
/**
* {@link jakarta.transaction.Transaction}の実装クラスです。
*
* @author higa
*/
public class TransactionImpl implements ExtendedTransaction,
SynchronizationRegister {
private static final int VOTE_READONLY = 0;
private static final int VOTE_COMMIT = 1;
private static final int VOTE_ROLLBACK = 2;
private static Logger logger = Logger.getLogger(TransactionImpl.class);
private Xid xid;
private int status = Status.STATUS_NO_TRANSACTION;
private List xaResourceWrappers = new ArrayList<>();
private List synchronizations = new ArrayList<>();
private List interposedSynchronizations = new ArrayList<>();
private Map resourceMap = new HashMap<>();
private boolean suspended = false;
private int branchId = 0;
/**
* TransactionImpl
のインスタンスを構築します。
*
*/
public TransactionImpl() {
}
/**
* トランザクションを開始します。
*
*/
@Override
public void begin() throws NotSupportedException, SystemException {
status = Status.STATUS_ACTIVE;
init();
if (logger.isDebugEnabled()) {
logger.log("DSSR0003", new Object[] { this });
}
}
/**
* トランザクションを中断します。
*
* @throws SystemException system exception
*/
@Override
public void suspend() throws SystemException {
assertNotSuspended();
assertActiveOrMarkedRollback();
for (int i = 0; i < getXAResourceWrapperSize(); ++i) {
XAResourceWrapper xarw = getXAResourceWrapper(i);
try {
xarw.end(XAResource.TMSUSPEND);
} catch (final XAException ex) {
throw new SSystemException("ESSR0363", new Object[] { ex }, ex);
}
}
suspended = true;
}
private void assertNotSuspended() throws IllegalStateException {
if (suspended) {
throw new SIllegalStateException("ESSR0314", null);
}
}
private void assertActive() throws IllegalStateException {
switch (status) {
case Status.STATUS_ACTIVE:
break;
default:
throwIllegalStateException();
}
}
private void throwIllegalStateException() throws IllegalStateException {
switch (status) {
case Status.STATUS_PREPARING:
throw new SIllegalStateException("ESSR0304", null);
case Status.STATUS_PREPARED:
throw new SIllegalStateException("ESSR0305", null);
case Status.STATUS_COMMITTING:
throw new SIllegalStateException("ESSR0306", null);
case Status.STATUS_COMMITTED:
throw new SIllegalStateException("ESSR0307", null);
case Status.STATUS_MARKED_ROLLBACK:
throw new SIllegalStateException("ESSR0308", null);
case Status.STATUS_ROLLING_BACK:
throw new SIllegalStateException("ESSR0309", null);
case Status.STATUS_ROLLEDBACK:
throw new SIllegalStateException("ESSR0310", null);
case Status.STATUS_NO_TRANSACTION:
throw new SIllegalStateException("ESSR0311", null);
case Status.STATUS_UNKNOWN:
throw new SIllegalStateException("ESSR0312", null);
default:
throw new SIllegalStateException("ESSR0032", new Object[] { String
.valueOf(status) });
}
}
private int getXAResourceWrapperSize() {
return xaResourceWrappers.size();
}
private XAResourceWrapper getXAResourceWrapper(int index) {
return xaResourceWrappers.get(index);
}
/**
* トランザクションを再開します。
*
* @throws SystemException system exceptiion
*/
@Override
public void resume() throws SystemException {
assertSuspended();
assertActiveOrMarkedRollback();
for (int i = 0; i < getXAResourceWrapperSize(); ++i) {
XAResourceWrapper xarw = getXAResourceWrapper(i);
try {
xarw.start(XAResource.TMRESUME);
} catch (final XAException ex) {
throw new SSystemException("ESSR0364", new Object[] { ex }, ex);
}
}
suspended = false;
}
private void assertSuspended() throws IllegalStateException {
if (!suspended) {
throw new SIllegalStateException("ESSR0315", null);
}
}
@Override
public void commit() throws RollbackException, HeuristicMixedException,
HeuristicRollbackException, SecurityException,
IllegalStateException, SystemException {
try {
assertNotSuspended();
assertActive();
beforeCompletion();
if (status == Status.STATUS_ACTIVE) {
endResources(XAResource.TMSUCCESS);
if (getXAResourceWrapperSize() == 0) {
status = Status.STATUS_COMMITTED;
} else if (getXAResourceWrapperSize() == 1) {
commitOnePhase();
} else {
switch (prepareResources()) {
case VOTE_READONLY:
status = Status.STATUS_COMMITTED;
break;
case VOTE_COMMIT:
commitTwoPhase();
break;
case VOTE_ROLLBACK:
rollbackForVoteOK();
}
}
if (status == Status.STATUS_COMMITTED) {
if (logger.isDebugEnabled()) {
logger.log("DSSR0004", new Object[] { this });
}
}
}
final boolean rolledBack = status != Status.STATUS_COMMITTED;
afterCompletion();
if (rolledBack) {
throw new SRollbackException("ESSR0303",
new Object[] { toString() });
}
} finally {
destroy();
}
}
private void beforeCompletion() {
for (int i = 0; i < getSynchronizationSize()
&& status == Status.STATUS_ACTIVE; ++i) {
beforeCompletion(getSynchronization(i));
}
for (int i = 0; i < getInterposedSynchronizationSize()
&& status == Status.STATUS_ACTIVE; ++i) {
beforeCompletion(getInterposedSynchronization(i));
}
}
private void beforeCompletion(Synchronization sync) {
try {
sync.beforeCompletion();
} catch (Throwable t) {
logger.log(t);
status = Status.STATUS_MARKED_ROLLBACK;
endResources(XAResource.TMFAIL);
rollbackResources();
}
}
private void endResources(int flag) {
for (int i = 0; i < getXAResourceWrapperSize(); ++i) {
XAResourceWrapper xarw = getXAResourceWrapper(i);
try {
xarw.end(flag);
} catch (Throwable t) {
logger.log(t);
status = Status.STATUS_MARKED_ROLLBACK;
}
}
}
private void commitOnePhase() {
status = Status.STATUS_COMMITTING;
XAResourceWrapper xari = getXAResourceWrapper(0);
try {
xari.commit(true);
status = Status.STATUS_COMMITTED;
} catch (Throwable t) {
logger.log(t);
status = Status.STATUS_UNKNOWN;
}
}
private int prepareResources() {
status = Status.STATUS_PREPARING;
int vote = VOTE_READONLY;
SLinkedList xarwList = new SLinkedList();
for (int i = 0; i < getXAResourceWrapperSize(); ++i) {
XAResourceWrapper xarw = getXAResourceWrapper(i);
if (xarw.isCommitTarget()) {
xarwList.addFirst(xarw);
}
}
for (int i = 0; i < xarwList.size(); ++i) {
XAResourceWrapper xarw = (XAResourceWrapper) xarwList.get(i);
try {
if (i == xarwList.size() - 1) {
// last resource commit optimization
xarw.commit(true);
xarw.setVoteOk(false);
vote = VOTE_COMMIT;
} else if (xarw.prepare() == XAResource.XA_OK) {
vote = VOTE_COMMIT;
} else {
xarw.setVoteOk(false);
}
} catch (Throwable t) {
logger.log(t);
xarw.setVoteOk(false);
status = Status.STATUS_MARKED_ROLLBACK;
return VOTE_ROLLBACK;
}
}
if (status == Status.STATUS_PREPARING) {
status = Status.STATUS_PREPARED;
}
return vote;
}
private void commitTwoPhase() {
status = Status.STATUS_COMMITTING;
for (int i = 0; i < getXAResourceWrapperSize(); ++i) {
XAResourceWrapper xarw = getXAResourceWrapper(i);
if (xarw.isCommitTarget() && xarw.isVoteOk()) {
try {
xarw.commit(false);
} catch (Throwable t) {
logger.log(t);
status = Status.STATUS_UNKNOWN;
}
}
}
if (status == Status.STATUS_COMMITTING) {
status = Status.STATUS_COMMITTED;
}
}
private void rollbackForVoteOK() {
status = Status.STATUS_ROLLING_BACK;
for (int i = 0; i < getXAResourceWrapperSize(); ++i) {
XAResourceWrapper xarw = getXAResourceWrapper(i);
if (xarw.isVoteOk()) {
try {
xarw.rollback();
} catch (Throwable t) {
logger.log(t);
status = Status.STATUS_UNKNOWN;
}
}
}
if (status == Status.STATUS_ROLLING_BACK) {
status = Status.STATUS_ROLLEDBACK;
}
}
private void afterCompletion() {
final int status = this.status;
this.status = Status.STATUS_NO_TRANSACTION;
for (int i = 0; i < getInterposedSynchronizationSize(); ++i) {
afterCompletion(status, getInterposedSynchronization(i));
}
for (int i = 0; i < getSynchronizationSize(); ++i) {
afterCompletion(status, getSynchronization(i));
}
}
private void afterCompletion(final int status, final Synchronization sync) {
try {
sync.afterCompletion(status);
} catch (Throwable t) {
logger.log(t);
}
}
private int getSynchronizationSize() {
return synchronizations.size();
}
private Synchronization getSynchronization(int index) {
return synchronizations.get(index);
}
private int getInterposedSynchronizationSize() {
return interposedSynchronizations.size();
}
private Synchronization getInterposedSynchronization(int index) {
return interposedSynchronizations.get(index);
}
@Override
public void rollback() throws IllegalStateException, SecurityException,
SystemException {
try {
assertNotSuspended();
assertActiveOrMarkedRollback();
endResources(XAResource.TMFAIL);
rollbackResources();
if (logger.isDebugEnabled()) {
logger.log("DSSR0005", new Object[] { this });
}
afterCompletion();
} finally {
destroy();
}
}
private void assertActiveOrMarkedRollback() throws IllegalStateException {
switch (status) {
case Status.STATUS_ACTIVE:
case Status.STATUS_MARKED_ROLLBACK:
break;
default:
throwIllegalStateException();
}
}
private void rollbackResources() {
status = Status.STATUS_ROLLING_BACK;
for (int i = 0; i < getXAResourceWrapperSize(); ++i) {
XAResourceWrapper xarw = getXAResourceWrapper(i);
try {
if (xarw.isCommitTarget()) {
xarw.rollback();
}
} catch (Throwable t) {
logger.log(t);
status = Status.STATUS_UNKNOWN;
}
}
if (status == Status.STATUS_ROLLING_BACK) {
status = Status.STATUS_ROLLEDBACK;
}
}
@Override
public void setRollbackOnly() throws IllegalStateException, SystemException {
assertNotSuspended();
assertActiveOrPreparingOrPrepared();
status = Status.STATUS_MARKED_ROLLBACK;
}
private void assertActiveOrPreparingOrPrepared()
throws IllegalStateException {
switch (status) {
case Status.STATUS_ACTIVE:
case Status.STATUS_PREPARING:
case Status.STATUS_PREPARED:
break;
default:
throwIllegalStateException();
}
}
@Override
public boolean enlistResource(XAResource xaResource)
throws RollbackException, IllegalStateException, SystemException {
boolean oracled = xaResource.getClass().getName().startsWith("oracle");
assertNotSuspended();
assertActive();
Xid xid = null;
for (int i = 0; i < getXAResourceWrapperSize(); ++i) {
XAResourceWrapper xarw = getXAResourceWrapper(i);
if (xaResource.equals(xarw.getXAResource())) {
return false;
} else if (oracled) {
continue;
} else {
try {
if (xaResource.isSameRM(xarw.getXAResource())) {
xid = xarw.getXid();
break;
}
} catch (XAException ex) {
throw new IllegalStateException(ex.toString());
}
}
}
int flag = xid == null ? XAResource.TMNOFLAGS : XAResource.TMJOIN;
boolean commitTarget = xid == null ? true : false;
if (xid == null) {
xid = createXidBranch();
}
try {
xaResource.start(xid, flag);
xaResourceWrappers.add(new XAResourceWrapper(xaResource, xid,
commitTarget));
return true;
} catch (XAException ex) {
IllegalStateException ise = new IllegalStateException(ex.toString());
ise.initCause(ex);
throw ise;
}
}
private Xid createXidBranch() {
return new XidImpl(xid, ++branchId);
}
@Override
public boolean delistResource(XAResource xaResource, int flag)
throws IllegalStateException, SystemException {
assertNotSuspended();
assertActiveOrMarkedRollback();
for (int i = 0; i < getXAResourceWrapperSize(); ++i) {
XAResourceWrapper xarw = getXAResourceWrapper(i);
if (xaResource.equals(xarw.getXAResource())) {
try {
xarw.end(flag);
return true;
} catch (XAException ex) {
logger.log(ex);
status = Status.STATUS_MARKED_ROLLBACK;
return false;
}
}
}
throw new SIllegalStateException("ESSR0313", null);
}
@Override
public int getStatus() {
return status;
}
@Override
public void registerSynchronization(Synchronization sync)
throws RollbackException, IllegalStateException, SystemException {
assertNotSuspended();
assertActive();
synchronizations.add(sync);
}
@Override
public void registerInterposedSynchronization(Synchronization sync)
throws IllegalStateException {
assertNotSuspended();
assertActive();
interposedSynchronizations.add(sync);
}
@Override
public void putResource(Object key, Object value)
throws IllegalStateException {
assertNotSuspended();
resourceMap.put(key, value);
}
@Override
public Object getResource(Object key) throws IllegalStateException {
assertNotSuspended();
return resourceMap.get(key);
}
/**
* トランザクションIDを返します。
*
* @return トランザクションID
*/
public Xid getXid() {
return xid;
}
/**
* トランザクションが中断されている場合はtrue
を、それ以外の場合はfalse
を返します。
*
* @return トランザクションが中断されている場合はtrue
*/
public boolean isSuspended() {
return suspended;
}
private void init() {
xid = new XidImpl();
}
private void destroy() {
status = Status.STATUS_NO_TRANSACTION;
xaResourceWrappers.clear();
synchronizations.clear();
interposedSynchronizations.clear();
resourceMap.clear();
suspended = false;
}
@Override
public String toString() {
return xid.toString();
}
/**
* {@link Synchronization}のリストを返します。
*
* @return List
*/
public List getSynchronizations() {
return synchronizations;
}
/**
* {@link Synchronization}のリストを返します。
*
* @return List
*/
public List getInterposedSynchronizations() {
return interposedSynchronizations;
}
}