/** * Alipay.com Inc. * Copyright (c) 2004-2012 All Rights Reserved. */ package com.alipay.zdal.datasource.tm; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; import com.alipay.zdal.datasource.resource.util.NestedRuntimeException; import com.alipay.zdal.datasource.transaction.RollbackException; import com.alipay.zdal.datasource.transaction.Synchronization; import com.alipay.zdal.datasource.transaction.SystemException; import com.alipay.zdal.datasource.transaction.Transaction; import com.alipay.zdal.datasource.transaction.TransactionManager; /** * An implementation of the transaction local implementation * using Transaction synchronizations. * * There is one of these per transaction local * * @author ���� * @version $Id: TransactionLocalDelegateImpl.java, v 0.1 2014-1-6 ����05:48:27 Exp $ */ public class TransactionLocalDelegateImpl implements TransactionLocalDelegate { // Attributes ---------------------------------------------------- /** The transaction manager */ protected TransactionManager manager; // Static -------------------------------------------------------- /** The synchronizations for each transaction */ protected static ConcurrentHashMap<Transaction, TransactionLocalSynchronization> synchronizationsByTransaction = new ConcurrentHashMap<Transaction, TransactionLocalSynchronization>(); /** * Retrieve a synchronization for the transaction * * @param tx the transaction * @param create whether to create a synchronization if one doesn't exist */ protected static TransactionLocalSynchronization getSynchronization(Transaction tx, boolean create) { synchronized (tx) { TransactionLocalSynchronization result = synchronizationsByTransaction.get(tx); if (result == null && create == true) { result = new TransactionLocalSynchronization(tx); try { tx.registerSynchronization(result); } catch (RollbackException e) { throw new IllegalStateException( "Transaction already rolled back or marked for rollback"); } catch (SystemException e) { throw new NestedRuntimeException(e); } synchronizationsByTransaction.put(tx, result); } return result; } } /** * Remove a synchronization * * @param tx the transaction to remove */ protected static void removeSynchronization(Transaction tx) { synchronizationsByTransaction.remove(tx); } // Constructor --------------------------------------------------- /** * Construct a new delegate for the given transaction manager * * @param manager the transaction manager */ public TransactionLocalDelegateImpl(TransactionManager manager) { this.manager = manager; } public void lock(TransactionLocal local, Transaction tx) throws InterruptedException { TransactionLocalSynchronization sync = getSynchronization(tx, true); sync.lock(local); } public void unlock(TransactionLocal local, Transaction tx) { TransactionLocalSynchronization sync = getSynchronization(tx, false); if (sync != null) sync.unlock(local); else throw new IllegalStateException("No synchronization found tx=" + tx + " local=" + local); } public Object getValue(TransactionLocal local, Transaction tx) { TransactionLocalSynchronization sync = getSynchronization(tx, false); if (sync == null) return null; return sync.getValue(local); } public void storeValue(TransactionLocal local, Transaction tx, Object value) { TransactionLocalSynchronization sync = getSynchronization(tx, true); sync.setValue(local, value); } public boolean containsValue(TransactionLocal local, Transaction tx) { TransactionLocalSynchronization sync = getSynchronization(tx, false); if (sync == null) return false; return sync.containsValue(local); } // InnerClasses --------------------------------------------------- protected static class TransactionLocalSynchronization implements Synchronization { protected Transaction tx; private Map valuesByLocal = Collections.synchronizedMap(new HashMap()); protected ReentrantLock reentrantLock = new ReentrantLock(); public TransactionLocalSynchronization(Transaction tx) { this.tx = tx; } public void beforeCompletion() { } public void afterCompletion(int status) { removeSynchronization(tx); valuesByLocal.clear(); // Help the GC } public void lock(Object local) throws InterruptedException { boolean locked = reentrantLock.tryLock(60000, TimeUnit.MILLISECONDS); if (locked == false) throw new IllegalStateException("Failed to acquire lock within 60 seconds."); } public void unlock(Object local) { reentrantLock.unlock(); } public Object getValue(Object local) { return valuesByLocal.get(local); } public void setValue(Object local, Object value) { valuesByLocal.put(local, value); } public boolean containsValue(Object local) { return valuesByLocal.containsKey(local); } } }