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: */
021: package net.sf.hajdbc.balancer;
022:
023: import java.util.Collections;
024: import java.util.Set;
025: import java.util.SortedSet;
026: import java.util.TreeSet;
027: import java.util.concurrent.locks.Lock;
028: import java.util.concurrent.locks.ReentrantLock;
029:
030: import net.sf.hajdbc.Balancer;
031: import 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: */
041: public abstract class AbstractBalancer<D> implements Balancer<D> {
042: protected Lock lock = new ReentrantLock();
043:
044: protected volatile SortedSet<Database<D>> databaseSet = new TreeSet<Database<D>>();
045:
046: /**
047: * @see net.sf.hajdbc.Balancer#beforeInvocation(net.sf.hajdbc.Database)
048: */
049: @Override
050: public void beforeInvocation(Database<D> database) {
051: // Do nothing
052: }
053:
054: /**
055: * @see net.sf.hajdbc.Balancer#afterInvocation(net.sf.hajdbc.Database)
056: */
057: @Override
058: public void afterInvocation(Database<D> database) {
059: // Do nothing
060: }
061:
062: /**
063: * @see net.sf.hajdbc.Balancer#remove(net.sf.hajdbc.Database)
064: */
065: @Override
066: public boolean remove(Database<D> database) {
067: this .lock.lock();
068:
069: try {
070: boolean exists = this .databaseSet.contains(database);
071:
072: if (exists) {
073: SortedSet<Database<D>> set = new TreeSet<Database<D>>(
074: this .databaseSet);
075:
076: set.remove(database);
077:
078: this .databaseSet = set;
079:
080: this .removed(database);
081: }
082:
083: return exists;
084: } finally {
085: this .lock.unlock();
086: }
087: }
088:
089: /**
090: * Called when a database was removed from the set.
091: * @param database a database descriptor
092: */
093: protected abstract void removed(Database<D> database);
094:
095: /**
096: * @see net.sf.hajdbc.Balancer#add(net.sf.hajdbc.Database)
097: */
098: @Override
099: public boolean add(Database<D> database) {
100: this .lock.lock();
101:
102: try {
103: boolean exists = this .databaseSet.contains(database);
104:
105: if (!exists) {
106: SortedSet<Database<D>> set = new TreeSet<Database<D>>(
107: this .databaseSet);
108:
109: set.add(database);
110:
111: this .databaseSet = set;
112:
113: this .added(database);
114: }
115:
116: return !exists;
117: } finally {
118: this .lock.unlock();
119: }
120: }
121:
122: /**
123: * Called when a database was added to the set.
124: * @param database a database descriptor
125: */
126: protected abstract void added(Database<D> database);
127:
128: /**
129: * @see net.sf.hajdbc.Balancer#all()
130: */
131: @Override
132: public Set<Database<D>> all() {
133: return Collections.unmodifiableSet(this .databaseSet);
134: }
135:
136: /**
137: * @see net.sf.hajdbc.Balancer#clear()
138: */
139: @Override
140: public void clear() {
141: this .lock.lock();
142:
143: try {
144: this .databaseSet = new TreeSet<Database<D>>();
145:
146: this .cleared();
147: } finally {
148: this .lock.unlock();
149: }
150: }
151:
152: /**
153: * Called when the set was cleared.
154: */
155: protected abstract void cleared();
156: }
|