001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.test.tm.resource;
023:
024: import java.io.Serializable;
025: import java.util.Collections;
026: import java.util.HashMap;
027: import java.util.Map;
028:
029: import javax.naming.InitialContext;
030: import javax.transaction.Synchronization;
031: import javax.transaction.Transaction;
032: import javax.transaction.TransactionManager;
033:
034: import org.jboss.logging.Logger;
035: import org.jboss.tm.TxUtils;
036:
037: /**
038: * MultiThreaded Operations that can be executed concurrently.
039: *
040: * Based on Operation class.
041: *
042: * @author <a href="dimitris@jboss.org">Dimitris Andreadis</a>
043: * @version $Revision: 57211 $
044: */
045: public class MTOperation implements Serializable {
046: // Static Data ---------------------------------------------------
047:
048: /** The serialVersionUID */
049: private static final long serialVersionUID = 2924873545494045020L;
050: /** Available Operations */
051: public static final int TM_GET_STATUS = 0;
052: public static final int TM_BEGIN = 1;
053: public static final int TM_RESUME = 2;
054: public static final int TM_COMMIT = 3;
055: public static final int TX_COMMIT = 4;
056: public static final int TX_REGISTER_SYNC = 5;
057: public static final int XX_SLEEP_200 = 6;
058: public static final int XX_WAIT_FOR = 7;
059:
060: /** The Logger */
061: protected static Logger log;
062:
063: /** TM instance */
064: protected static TransactionManager tm = null;
065:
066: /** Shared resources */
067: protected static Map resources = Collections
068: .synchronizedMap(new HashMap());
069:
070: /** Active Transactions */
071: protected static Map transactions = Collections
072: .synchronizedMap(new HashMap());
073:
074: // Protected Data ------------------------------------------------
075:
076: /** An id for this transaction */
077: protected Integer id;
078:
079: /** The operation to execute */
080: protected int op;
081:
082: /** Set when an exception is expected */
083: protected Throwable throwable;
084:
085: // Static Methods ------------------------------------------------
086:
087: /**
088: * Setup static objects for the test
089: */
090: public static void init(Logger log) throws Exception {
091: MTOperation.log = log;
092:
093: if (getTM().getTransaction() != null) {
094: throw new IllegalStateException(
095: "Invalid thread association "
096: + getTM().getTransaction());
097: }
098: resources.clear();
099: transactions.clear();
100: }
101:
102: /**
103: * Lazy TransactionManager lookup
104: */
105: public static TransactionManager getTM() throws Exception {
106: if (tm == null) {
107: tm = (TransactionManager) new InitialContext()
108: .lookup("java:/TransactionManager");
109: }
110: return tm;
111: }
112:
113: /**
114: * Cleanup
115: */
116: public static void destroy() {
117: resources.clear();
118: transactions.clear();
119: }
120:
121: // Constructors --------------------------------------------------
122:
123: public MTOperation(int op) {
124: this (op, 0);
125: }
126:
127: public MTOperation(int op, int id) {
128: this .id = new Integer(id);
129: this .op = op;
130: }
131:
132: public MTOperation(int op, int id, Throwable throwable) {
133: this .id = new Integer(id);
134: this .op = op;
135: this .throwable = throwable;
136: }
137:
138: // Public Methods ------------------------------------------------
139:
140: public void perform() throws Exception {
141: Throwable caught = null;
142: try {
143: switch (op) {
144: case TM_GET_STATUS:
145: tmGetStatus();
146: break;
147:
148: case TM_BEGIN:
149: tmBegin();
150: break;
151:
152: case TM_RESUME:
153: tmResume();
154: break;
155:
156: case TM_COMMIT:
157: tmCommit();
158: break;
159:
160: case TX_COMMIT:
161: txCommit();
162: break;
163:
164: case TX_REGISTER_SYNC:
165: txRegisterSync();
166: break;
167:
168: case XX_SLEEP_200:
169: xxSleep200();
170: break;
171:
172: case XX_WAIT_FOR:
173: xxWaitForTx();
174: break;
175:
176: default:
177: throw new IllegalArgumentException("Invalid operation "
178: + op);
179: }
180: } catch (Throwable t) {
181: caught = t;
182: }
183:
184: // expected an exception but caught none
185: if (throwable != null && caught == null) {
186: throw new Exception("Expected throwable " + throwable);
187: }
188:
189: // expected an exception but caught the wrong one
190: if (throwable != null
191: && (throwable.getClass().isAssignableFrom(caught
192: .getClass())) == false) {
193: log.warn("Caught wrong throwable", caught);
194: throw new Exception("Expected throwable " + throwable
195: + " caught " + caught);
196: }
197:
198: // did not expect an exception bug caught one
199: if (throwable == null && caught != null) {
200: log.warn("Caught unexpected throwable", caught);
201: throw new Exception("Unexpected throwable " + caught);
202: }
203: }
204:
205: public void tmGetStatus() throws Exception {
206: log.info(tid() + " "
207: + TxUtils.getStatusAsString(getTM().getStatus()));
208: }
209:
210: public void tmBegin() throws Exception {
211: log.info(tid() + " TM_BEGIN (" + id + ")");
212: getTM().begin();
213: Transaction tx = getTM().getTransaction();
214: synchronized (transactions) {
215: transactions.put(id, tx);
216: transactions.notifyAll();
217: }
218: }
219:
220: public void tmResume() throws Exception {
221: log.info(tid() + " TM_RESUME (" + id + ")");
222: Transaction tx = (Transaction) transactions.get(id);
223: if (tx == null) {
224: throw new IllegalStateException("Tx not found:" + id);
225: } else {
226: getTM().resume(tx);
227: }
228: }
229:
230: public void tmCommit() throws Exception {
231: log.info(tid() + " TM_COMMIT");
232: getTM().commit();
233: }
234:
235: public void txCommit() throws Exception {
236: log.info(tid() + " TX_COMMIT (" + id + ")");
237: Transaction tx = (Transaction) transactions.get(id);
238: if (tx == null) {
239: throw new IllegalStateException("Tx not found: " + id);
240: } else {
241: tx.commit();
242: }
243: }
244:
245: public void txRegisterSync() throws Exception {
246: log.info(tid() + " TX_REGISTER_SYNC (" + id + ")");
247: Transaction tx = (Transaction) transactions.get(id);
248: if (tx == null) {
249: throw new IllegalStateException("Tx not found: " + id);
250: }
251: Synchronization sync = new Synchronization() {
252: public void beforeCompletion() {
253: log.info(tid() + " beforeCompletion() called");
254: }
255:
256: public void afterCompletion(int status) {
257: log.info(tid() + " afterCompletion("
258: + TxUtils.getStatusAsString(status)
259: + ") called");
260: }
261: };
262: tx.registerSynchronization(sync);
263: }
264:
265: public void xxWaitForTx() throws Exception {
266: log.info(tid() + " XX_WAIT_FOR (" + id + ")");
267:
268: Transaction tx = (Transaction) transactions.get(id);
269: while (tx == null) {
270: log.info(tid() + " Sleeping for 100 msecs");
271: synchronized (transactions) {
272: try {
273: transactions.wait(100);
274: } catch (InterruptedException ignore) {
275: }
276: }
277: tx = (Transaction) transactions.get(id);
278: }
279: log.info(tid() + " Got it");
280: }
281:
282: public void xxSleep200() throws Exception {
283: log.info(tid() + " XX_SLEEP_200");
284: Thread.sleep(200);
285: }
286:
287: private String tid() {
288: return Thread.currentThread().getName();
289: }
290: }
|