/* * 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. } } } }