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.tm;
023:
024: import java.util.Collections;
025: import java.util.HashMap;
026: import java.util.Map;
027:
028: import javax.transaction.RollbackException;
029: import javax.transaction.Synchronization;
030: import javax.transaction.SystemException;
031: import javax.transaction.Transaction;
032: import javax.transaction.TransactionManager;
033:
034: import org.jboss.util.NestedRuntimeException;
035:
036: import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
037: import EDU.oswego.cs.dl.util.concurrent.ReentrantLock;
038:
039: /**
040: * An implementation of the transaction local implementation
041: * using Transaction synchronizations.
042: *
043: * There is one of these per transaction local
044: *
045: * @author <a href="mailto:adrian@jboss.org">Adrian Brock</a>
046: * @version $Revision: 57208 $
047: */
048: public class TransactionLocalDelegateImpl implements
049: TransactionLocalDelegate {
050: // Attributes ----------------------------------------------------
051:
052: /** The transaction manager */
053: protected TransactionManager manager;
054:
055: // Static --------------------------------------------------------
056:
057: /** The synchronizations for each transaction */
058: protected static ConcurrentHashMap synchronizationsByTransaction = new ConcurrentHashMap();
059:
060: /**
061: * Retrieve a synchronization for the transaction
062: *
063: * @param tx the transaction
064: * @param create whether to create a synchronization if one doesn't exist
065: */
066: protected static TransactionLocalSynchronization getSynchronization(
067: Transaction tx, boolean create) {
068: synchronized (tx) {
069: TransactionLocalSynchronization result = (TransactionLocalSynchronization) synchronizationsByTransaction
070: .get(tx);
071: if (result == null && create == true) {
072: result = new TransactionLocalSynchronization(tx);
073: try {
074: tx.registerSynchronization(result);
075: } catch (RollbackException e) {
076: throw new IllegalStateException(
077: "Transaction already rolled back or marked for rollback");
078: } catch (SystemException e) {
079: throw new NestedRuntimeException(e);
080: }
081: synchronizationsByTransaction.put(tx, result);
082: }
083: return result;
084: }
085: }
086:
087: /**
088: * Remove a synchronization
089: *
090: * @param tx the transaction to remove
091: */
092: protected static void removeSynchronization(Transaction tx) {
093: synchronizationsByTransaction.remove(tx);
094: }
095:
096: // Constructor ---------------------------------------------------
097:
098: /**
099: * Construct a new delegate for the given transaction manager
100: *
101: * @param manager the transaction manager
102: */
103: public TransactionLocalDelegateImpl(TransactionManager manager) {
104: this .manager = manager;
105: }
106:
107: public void lock(TransactionLocal local, Transaction tx)
108: throws InterruptedException {
109: TransactionLocalSynchronization sync = getSynchronization(tx,
110: true);
111: sync.lock(local);
112: }
113:
114: public void unlock(TransactionLocal local, Transaction tx) {
115: TransactionLocalSynchronization sync = getSynchronization(tx,
116: false);
117: if (sync != null)
118: sync.unlock(local);
119: else
120: throw new IllegalStateException(
121: "No synchronization found tx=" + tx + " local="
122: + local);
123: }
124:
125: public Object getValue(TransactionLocal local, Transaction tx) {
126: TransactionLocalSynchronization sync = getSynchronization(tx,
127: false);
128: if (sync == null)
129: return null;
130: return sync.getValue(local);
131: }
132:
133: public void storeValue(TransactionLocal local, Transaction tx,
134: Object value) {
135: TransactionLocalSynchronization sync = getSynchronization(tx,
136: true);
137: sync.setValue(local, value);
138: }
139:
140: public boolean containsValue(TransactionLocal local, Transaction tx) {
141: TransactionLocalSynchronization sync = getSynchronization(tx,
142: false);
143: if (sync == null)
144: return false;
145: return sync.containsValue(local);
146: }
147:
148: // InnerClasses ---------------------------------------------------
149:
150: protected static class TransactionLocalSynchronization implements
151: Synchronization {
152: protected Transaction tx;
153:
154: private Map valuesByLocal = Collections
155: .synchronizedMap(new HashMap());
156:
157: protected ReentrantLock reentrantLock = new ReentrantLock();
158:
159: public TransactionLocalSynchronization(Transaction tx) {
160: this .tx = tx;
161: }
162:
163: public void beforeCompletion() {
164: }
165:
166: public void afterCompletion(int status) {
167: removeSynchronization(tx);
168: valuesByLocal.clear(); // Help the GC
169: }
170:
171: public void lock(Object local) throws InterruptedException {
172: boolean locked = reentrantLock.attempt(60000);
173: if (locked == false)
174: throw new IllegalStateException(
175: "Failed to acquire lock within 60 seconds.");
176: }
177:
178: public void unlock(Object local) {
179: reentrantLock.release();
180: }
181:
182: public Object getValue(Object local) {
183: return valuesByLocal.get(local);
184: }
185:
186: public void setValue(Object local, Object value) {
187: valuesByLocal.put(local, value);
188: }
189:
190: public boolean containsValue(Object local) {
191: return valuesByLocal.containsKey(local);
192: }
193: }
194: }
|