/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.test.tm.resource; import java.io.Serializable; import java.util.HashMap; import javax.naming.InitialContext; import javax.transaction.Status; import javax.transaction.Transaction; import javax.transaction.TransactionManager; import org.jboss.logging.Logger; /** * Operations * @author Adrian@jboss.org * @version $Revision: 81036 $ */ public class Operation implements Serializable { static final long serialVersionUID = 6263843332702708629L; public static final int BEGIN = -1; public static final int COMMIT = -2; public static final int ROLLBACK = -3; public static final int SUSPEND = -4; public static final int RESUME = -5; public static final int SETROLLBACK = -6; public static final int STATUS = -7; public static final int STATE = 0; public static final int CREATE = 1; public static final int ENLIST = 2; public static final int DIFFRM = 3; public static final int SETSTATUS = 4; public static final int CREATE_LOCAL = 5; public static final int FAIL_LOCAL = 6; static HashMap resources = new HashMap(); static HashMap transactions = new HashMap(); static Logger log; static TransactionManager tm = null; Integer id; int op; int status; Throwable throwable; public Operation(int op, int id) { this(op, id, 0); } public Operation(int op, int id, int status) { this(op, id, status, null); } public Operation(int op, int id, int status, Throwable throwable) { this.id = new Integer(id); this.op = op; this.status = status; this.throwable = throwable; } public void perform() throws Exception { Throwable caught = null; try { switch (op) { case BEGIN: begin(); break; case COMMIT: commit(); break; case ROLLBACK: rollback(); break; case SUSPEND: suspend(); break; case RESUME: resume(); break; case SETROLLBACK: setRollbackOnly(); break; case STATUS: checkStatus(); break; case STATE: checkState(); break; case CREATE: create(); break; case CREATE_LOCAL: createLocal(); break; case FAIL_LOCAL: failLocal(); break; case ENLIST: enlist(); break; case DIFFRM: differentRM(); break; case SETSTATUS: setStatus(); break; default: throw new IllegalArgumentException("Invalid operation " + op); } } catch (Throwable t) { caught = t; } if (throwable != null && caught == null) throw new Exception("Expected throwable " + throwable); if (throwable != null && (throwable.getClass().isAssignableFrom(caught.getClass())) == false) { caught.printStackTrace(); throw new Exception("Expected throwable " + throwable + " was " + caught); } if (throwable == null && caught != null) { caught.printStackTrace(); throw new Exception("Unexpected throwable " + caught); } } public void begin() throws Exception { log.info("BEGIN " + id); getTM().begin(); Transaction tx = getTM().getTransaction(); transactions.put(id, tx); log.info("BEGUN " + tx); } public void commit() throws Exception { log.info("COMMIT " + id); assertTx(id); getTM().commit(); int status = getTM().getStatus(); if (Status.STATUS_NO_TRANSACTION != status) throw new Exception("Expected no thread association after commit status=" + status); log.info("COMMITTED " + id); } public void rollback() throws Exception { log.info("ROLLBACK " + id); assertTx(id); getTM().rollback(); int status = getTM().getStatus(); if (Status.STATUS_NO_TRANSACTION != status) throw new Exception("Expected no thread association after rollback status=" + status); log.info("ROLLEDBACK " + id); } public void suspend() throws Exception { log.info("SUSPEND " + id); assertTx(id); getTM().suspend(); log.info("SUSPENDED " + id); } public void resume() throws Exception { log.info("RESUME " + id); getTM().resume(getTx(id)); assertTx(id); log.info("RESUMED " + id); } public void setRollbackOnly() throws Exception { log.info("SETROLLBACK " + id); getTx(id).setRollbackOnly(); log.info("SETTEDROLLBACK " + id); } public void checkStatus() throws Exception { log.info("CHECKSTATUS " + id); int actualStatus = getTx(id).getStatus(); log.info("CHECKINGSTATUS " + id + " Expected " + status + " was " + actualStatus); if (actualStatus != status) throw new Exception("Transaction " + id + " Expected status " + status + " was " + actualStatus); } public void checkState() throws Exception { log.info("CHECKSTATE " + id); int actualStatus = getRes(id).getStatus(); log.info("CHECKINGSTATE " + id + " Expected " + status + " was " + actualStatus); if (actualStatus != status) throw new Exception("Resource " + id + " Expected state " + status + " was " + actualStatus); } public void create() throws Exception { log.info("CREATE " + id); Resource res = new Resource(id); resources.put(id, res); log.info("CREATED " + res); } public void createLocal() throws Exception { log.info("CREATE_LOCAL " + id); Resource res = new LocalResource(id); resources.put(id, res); log.info("CREATED_LOCAL " + res); } public void enlist() throws Exception { log.info("ENLIST " + id); Transaction tx = getTM().getTransaction(); if (tx.enlistResource(getRes(id)) == false) throw new Exception("Unable to enlist resource"); log.info("ENLISTED " + id + " " + tx); } public void differentRM() throws Exception { log.info("DIFFRM " + id); getRes(id).newResourceManager(); } public void failLocal() throws Exception { log.info("FAIL_LOCAL " + id); LocalResource resource = (LocalResource) getRes(id); resource.failLocal(); } public void setStatus() throws Exception { log.info("SETSTATUS " + id + " " + status); getRes(id).setStatus(status); log.info("SETTEDSTATUS " + id + " " + status); } public static void start(Logger log) throws Exception { Operation.log = log; if (getTM().getTransaction() != null) throw new IllegalStateException("Invalid thread association " + getTM().getTransaction()); reset(); } public static void end() { reset(); } public static void reset() { resources.clear(); transactions.clear(); } public static void tidyUp() { try { if (getTM().getStatus() != Status.STATUS_NO_TRANSACTION) { log.warn("TIDYING UP AFTER BROKEN TEST!"); getTM().rollback(); } } catch (Exception ignored) { } } public Resource getRes(Integer id) { Resource res = (Resource) resources.get(id); if (res == null) throw new IllegalStateException("No resource: " + id); return res; } public Transaction getTx(Integer id) { Transaction tx = (Transaction) transactions.get(id); if (tx == null) throw new IllegalStateException("No transaction: " + id); return tx; } public void assertTx(Integer id) throws Exception { Transaction tx = getTx(id); Transaction current = getTM().getTransaction(); log.info("Asserting tx " + tx + " current " + current); if (tx.equals(current) == false) throw new IllegalStateException("Expected tx " + tx + " was " + current); } public static TransactionManager getTM() throws Exception { if (tm == null) tm = (TransactionManager) new InitialContext().lookup("java:/TransactionManager"); return tm; } }