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