001/* 002 * HA-JDBC: High-Availability JDBC 003 * Copyright (c) 2004-2007 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.balancer; 022 023import java.util.Collections; 024import java.util.Set; 025import java.util.SortedSet; 026import java.util.TreeSet; 027import java.util.concurrent.locks.Lock; 028import java.util.concurrent.locks.ReentrantLock; 029 030import net.sf.hajdbc.Balancer; 031import net.sf.hajdbc.Database; 032 033/** 034 * Thread-safe abstract balancer implementation that implements most of the Balancer interface, except {@link Balancer#next()}. 035 * Uses A copy-on-write algorithm for {@link #add(Database)}, {@link #remove(Database)}, and {@link #clear()}. 036 * Calls to {@link #all()} are non-blocking. 037 * 038 * @author Paul Ferraro 039 * @param <D> either java.sql.Driver or javax.sql.DataSource 040 */ 041public abstract class AbstractBalancer<D> implements Balancer<D> 042{ 043 protected Lock lock = new ReentrantLock(); 044 045 protected volatile SortedSet<Database<D>> databaseSet = new TreeSet<Database<D>>(); 046 047 /** 048 * @see net.sf.hajdbc.Balancer#beforeInvocation(net.sf.hajdbc.Database) 049 */ 050 @Override 051 public void beforeInvocation(Database<D> database) 052 { 053 // Do nothing 054 } 055 056 /** 057 * @see net.sf.hajdbc.Balancer#afterInvocation(net.sf.hajdbc.Database) 058 */ 059 @Override 060 public void afterInvocation(Database<D> database) 061 { 062 // Do nothing 063 } 064 065 /** 066 * @see net.sf.hajdbc.Balancer#remove(net.sf.hajdbc.Database) 067 */ 068 @Override 069 public boolean remove(Database<D> database) 070 { 071 this.lock.lock(); 072 073 try 074 { 075 boolean exists = this.databaseSet.contains(database); 076 077 if (exists) 078 { 079 SortedSet<Database<D>> set = new TreeSet<Database<D>>(this.databaseSet); 080 081 set.remove(database); 082 083 this.databaseSet = set; 084 085 this.removed(database); 086 } 087 088 return exists; 089 } 090 finally 091 { 092 this.lock.unlock(); 093 } 094 } 095 096 /** 097 * Called when a database was removed from the set. 098 * @param database a database descriptor 099 */ 100 protected abstract void removed(Database<D> database); 101 102 /** 103 * @see net.sf.hajdbc.Balancer#add(net.sf.hajdbc.Database) 104 */ 105 @Override 106 public boolean add(Database<D> database) 107 { 108 this.lock.lock(); 109 110 try 111 { 112 boolean exists = this.databaseSet.contains(database); 113 114 if (!exists) 115 { 116 SortedSet<Database<D>> set = new TreeSet<Database<D>>(this.databaseSet); 117 118 set.add(database); 119 120 this.databaseSet = set; 121 122 this.added(database); 123 } 124 125 return !exists; 126 } 127 finally 128 { 129 this.lock.unlock(); 130 } 131 } 132 133 /** 134 * Called when a database was added to the set. 135 * @param database a database descriptor 136 */ 137 protected abstract void added(Database<D> database); 138 139 /** 140 * @see net.sf.hajdbc.Balancer#all() 141 */ 142 @Override 143 public Set<Database<D>> all() 144 { 145 return Collections.unmodifiableSet(this.databaseSet); 146 } 147 148 /** 149 * @see net.sf.hajdbc.Balancer#clear() 150 */ 151 @Override 152 public void clear() 153 { 154 this.lock.lock(); 155 156 try 157 { 158 this.databaseSet = new TreeSet<Database<D>>(); 159 160 this.cleared(); 161 } 162 finally 163 { 164 this.lock.unlock(); 165 } 166 } 167 168 /** 169 * Called when the set was cleared. 170 */ 171 protected abstract void cleared(); 172}