/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.ode.test;
import java.util.ArrayList;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.InvalidTransactionException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAResource;
/**
* A minimal transaction manager that can be used for testing.
*
* @author Maciej Szefler <mszefler at gmail dot com>
*
*/
public class MockTransactionManager implements TransactionManager {
ThreadLocal<TX> _transaction = new ThreadLocal<TX>();
public void begin() throws NotSupportedException, SystemException {
if (_transaction.get() != null)
throw new NotSupportedException("Transaction active (nested tx not supported): " + _transaction.get());
_transaction.set(new TX());
}
public void commit() throws HeuristicMixedException, HeuristicRollbackException, IllegalStateException, RollbackException,
SecurityException, SystemException {
if (_transaction.get() == null)
throw new IllegalStateException("Transaction not active. ");
try {
_transaction.get().commit();
} finally {
_transaction.set(null);
}
}
public int getStatus() throws SystemException {
if (_transaction.get() == null)
return Status.STATUS_NO_TRANSACTION;
return _transaction.get().getStatus();
}
public Transaction getTransaction() throws SystemException {
return _transaction.get();
}
public void resume(Transaction tx) throws IllegalStateException, InvalidTransactionException, SystemException {
if (_transaction.get() != null)
throw new IllegalStateException("Transaction is active in current thread: " + _transaction.get());
try {
_transaction.set((TX) tx);
} catch (ClassCastException cce) {
throw new InvalidTransactionException();
}
}
public void rollback() throws IllegalStateException, SecurityException, SystemException {
if (_transaction.get() == null)
throw new IllegalStateException("Transaction not active. ");
try {
_transaction.get().rollback();
} finally {
_transaction.set(null);
}
}
public void setRollbackOnly() throws IllegalStateException, SystemException {
if (_transaction.get() == null)
throw new IllegalStateException("Transaction not active. ");
_transaction.get().setRollbackOnly();
}
public void setTransactionTimeout(int arg0) throws SystemException {
// TODO Auto-generated method stub
}
public Transaction suspend() throws SystemException {
try {
return _transaction.get();
} finally {
_transaction.set(null);
}
}
protected void doBegin(TX tx) {}
protected void doCommit(TX tx) {}
protected void doRollback(TX tx){}
public class TX implements Transaction {
final ArrayList<XAResource> _resources = new ArrayList<XAResource>();
final ArrayList<Synchronization> _synchros = new ArrayList<Synchronization> ();
private int _status;
public void commit() throws HeuristicMixedException, HeuristicRollbackException, RollbackException, SecurityException,
SystemException {
switch (_status) {
case Status.STATUS_COMMITTED:
return;
case Status.STATUS_MARKED_ROLLBACK:
rollback();
throw new RollbackException("Transaction was marked for rollback!");
case Status.STATUS_ACTIVE:
fireBefore();
if (_status == Status.STATUS_MARKED_ROLLBACK) {
rollback();
throw new RollbackException("Transaction was marked for rollback in beforeCompletion handler.");
}
_status = Status.STATUS_COMMITTING;
try {
doCommit(this);
_status = Status.STATUS_COMMITTED;
} catch (Exception ex) {
_status = Status.STATUS_ROLLEDBACK;
throw new RollbackException("Transaction was rolled back due to commit failure." );
} finally {
fireAfter();
}
break;
default:
throw new IllegalStateException("Unexpected transaction state.");
}
}
public boolean delistResource(XAResource arg0, int arg1) throws IllegalStateException, SystemException {
// TODO: perhaps we should do something with the resources?
_resources.remove(arg0);
return true;
}
public boolean enlistResource(XAResource r) throws IllegalStateException, RollbackException, SystemException {
return _resources.add(r);
}
public int getStatus() throws SystemException {
return _status;
}
public void registerSynchronization(Synchronization synch) throws IllegalStateException, RollbackException, SystemException {
_synchros.add(synch);
}
public void rollback() throws IllegalStateException, SystemException {
// TODO Auto-generated method stub
switch (_status) {
case Status.STATUS_ROLLEDBACK:
return;
case Status.STATUS_MARKED_ROLLBACK:
case Status.STATUS_ACTIVE:
_status = Status.STATUS_ROLLING_BACK;
try {
doRollback(this);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
_status = Status.STATUS_ROLLEDBACK;
fireAfter();
}
break;
default:
throw new IllegalStateException("Unexpected transaction state.");
}
}
public void setRollbackOnly() throws IllegalStateException, SystemException {
switch (_status) {
case Status.STATUS_ACTIVE:
case Status.STATUS_MARKED_ROLLBACK:
_status = Status.STATUS_MARKED_ROLLBACK;
break;
case Status.STATUS_ROLLEDBACK:
case Status.STATUS_ROLLING_BACK:
break;
default:
throw new IllegalStateException();
}
}
private void fireBefore() {
for (Synchronization s : _synchros)
try {
s.beforeCompletion();
} catch (Throwable t) {
; // ignore errors.
}
}
private void fireAfter() {
for (Synchronization s : _synchros)
try {
s.afterCompletion(_status);
} catch (Throwable t) {
; // ignore errors.
}
}
}
}