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}