001/* 002 * HA-JDBC: High-Availability JDBC 003 * Copyright (c) 2004-2008 Paul Ferraro 004 * 005 * This library is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU Lesser General Public License as published by the 007 * Free Software Foundation; either version 2.1 of the License, or (at your 008 * option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, but WITHOUT 011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 013 * for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public License 016 * along with this library; if not, write to the Free Software Foundation, 017 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018 * 019 * Contact: ferraro@users.sourceforge.net 020 */ 021package net.sf.hajdbc.sql; 022 023import java.sql.Connection; 024import java.sql.SQLException; 025import java.util.Collections; 026import java.util.concurrent.locks.Lock; 027 028import net.sf.hajdbc.DatabaseCluster; 029import net.sf.hajdbc.LockManager; 030 031/** 032 * @author Paul Ferraro 033 * @param <D> 034 */ 035public class LocalTransactionContext<D> implements TransactionContext<D> 036{ 037 private Lock lock; 038 private boolean locked = false; 039 040 /** 041 * @param cluster 042 */ 043 public LocalTransactionContext(DatabaseCluster<D> cluster) 044 { 045 this.lock = cluster.getLockManager().readLock(LockManager.GLOBAL); 046 } 047 048 /** 049 * @see net.sf.hajdbc.sql.TransactionContext#start(net.sf.hajdbc.sql.InvocationStrategy, java.sql.Connection) 050 */ 051 public <T, R> InvocationStrategy<D, T, R> start(final InvocationStrategy<D, T, R> strategy, Connection connection) throws SQLException 052 { 053 if (this.locked) return strategy; 054 055 if (connection.getAutoCommit()) 056 { 057 return new LockingInvocationStrategy<D, T, R>(strategy, Collections.singletonList(this.lock)); 058 } 059 060 return new InvocationStrategy<D, T, R>() 061 { 062 @Override 063 public R invoke(SQLProxy<D, T> proxy, Invoker<D, T, R> invoker) throws Exception 064 { 065 LocalTransactionContext.this.lock(); 066 067 try 068 { 069 return strategy.invoke(proxy, invoker); 070 } 071 catch (Exception e) 072 { 073 LocalTransactionContext.this.unlock(); 074 075 throw e; 076 } 077 } 078 }; 079 } 080 081 /** 082 * @see net.sf.hajdbc.sql.TransactionContext#end(net.sf.hajdbc.sql.InvocationStrategy) 083 */ 084 public <T, R> InvocationStrategy<D, T, R> end(final InvocationStrategy<D, T, R> strategy) 085 { 086 if (!this.locked) return strategy; 087 088 return new InvocationStrategy<D, T, R>() 089 { 090 @Override 091 public R invoke(SQLProxy<D, T> proxy, Invoker<D, T, R> invoker) throws Exception 092 { 093 try 094 { 095 return strategy.invoke(proxy, invoker); 096 } 097 finally 098 { 099 LocalTransactionContext.this.unlock(); 100 } 101 } 102 }; 103 } 104 105 /** 106 * @see net.sf.hajdbc.sql.TransactionContext#close() 107 */ 108 @Override 109 public void close() 110 { 111 // Tsk, tsk... User neglected to commit/rollback transaction 112 if (this.locked) 113 { 114 this.unlock(); 115 } 116 } 117 118 void lock() 119 { 120 this.lock.lock(); 121 this.locked = true; 122 } 123 124 void unlock() 125 { 126 this.lock.unlock(); 127 this.locked = false; 128 } 129}