KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jahia > tools > db > ConnectionPool


1 package org.jahia.tools.db;
2
3 import java.sql.*;
4 import java.util.*;
5
6 /** A class for preallocating, recycling, and managing
7  * JDBC connections.
8  * <P>
9  * Taken from Core Servlets and JavaServer Pages
10  * from Prentice Hall and Sun Microsystems Press,
11  * http://www.coreservlets.com/.
12  * &copy; 2000 Marty Hall; may be freely used or adapted.
13  */

14
15 public class ConnectionPool implements Runnable JavaDoc {
16   private String JavaDoc driver, url, username, password;
17   private int maxConnections;
18   private boolean waitIfBusy;
19   private Vector availableConnections, busyConnections;
20   private boolean connectionPending = false;
21
22   public ConnectionPool(String JavaDoc driver, String JavaDoc url,
23                         String JavaDoc username, String JavaDoc password,
24                         int initialConnections,
25                         int maxConnections,
26                         boolean waitIfBusy)
27       throws SQLException {
28     this.driver = driver;
29     this.url = url;
30     this.username = username;
31     this.password = password;
32     this.maxConnections = maxConnections;
33     this.waitIfBusy = waitIfBusy;
34     if (initialConnections > maxConnections) {
35       initialConnections = maxConnections;
36     }
37     availableConnections = new Vector(initialConnections);
38     busyConnections = new Vector();
39     for(int i=0; i<initialConnections; i++) {
40       availableConnections.addElement(makeNewConnection());
41     }
42   }
43
44   public synchronized Connection getConnection()
45       throws SQLException {
46     if (!availableConnections.isEmpty()) {
47       Connection existingConnection =
48         (Connection)availableConnections.lastElement();
49       int lastIndex = availableConnections.size() - 1;
50       availableConnections.removeElementAt(lastIndex);
51       // If connection on available list is closed (e.g.,
52
// it timed out), then remove it from available list
53
// and repeat the process of obtaining a connection.
54
// Also wake up threads that were waiting for a
55
// connection because maxConnection limit was reached.
56
if (existingConnection.isClosed()) {
57         notifyAll(); // Freed up a spot for anybody waiting
58
return(getConnection());
59       } else {
60         busyConnections.addElement(existingConnection);
61         return(existingConnection);
62       }
63     } else {
64
65       // Three possible cases:
66
// 1) You haven't reached maxConnections limit. So
67
// establish one in the background if there isn't
68
// already one pending, then wait for
69
// the next available connection (whether or not
70
// it was the newly established one).
71
// 2) You reached maxConnections limit and waitIfBusy
72
// flag is false. Throw SQLException in such a case.
73
// 3) You reached maxConnections limit and waitIfBusy
74
// flag is true. Then do the same thing as in second
75
// part of step 1: wait for next available connection.
76

77       if ((totalConnections() < maxConnections) &&
78           !connectionPending) {
79         makeBackgroundConnection();
80       } else if (!waitIfBusy) {
81         throw new SQLException("Connection limit reached");
82       }
83       // Wait for either a new connection to be established
84
// (if you called makeBackgroundConnection) or for
85
// an existing connection to be freed up.
86
try {
87         wait();
88       } catch(InterruptedException JavaDoc ie) {}
89       // Someone freed up a connection, so try again.
90
return(getConnection());
91     }
92   }
93
94   // You can't just make a new connection in the foreground
95
// when none are available, since this can take several
96
// seconds with a slow network connection. Instead,
97
// start a thread that establishes a new connection,
98
// then wait. You get woken up either when the new connection
99
// is established or if someone finishes with an existing
100
// connection.
101

102   private void makeBackgroundConnection() {
103     connectionPending = true;
104     try {
105       Thread JavaDoc connectThread = new Thread JavaDoc(this);
106       connectThread.start();
107     } catch(OutOfMemoryError JavaDoc oome) {
108       // Give up on new connection
109
}
110   }
111
112   public void run() {
113     try {
114       Connection connection = makeNewConnection();
115       synchronized(this) {
116         availableConnections.addElement(connection);
117         connectionPending = false;
118         notifyAll();
119       }
120     } catch(Exception JavaDoc e) { // SQLException or OutOfMemory
121
// Give up on new connection and wait for existing one
122
// to free up.
123
}
124   }
125
126   // This explicitly makes a new connection. Called in
127
// the foreground when initializing the ConnectionPool,
128
// and called in the background when running.
129

130   private Connection makeNewConnection()
131       throws SQLException {
132     try {
133       // Load database driver if not already loaded
134
Class.forName(driver);
135       // Establish network connection to database
136
Connection connection =
137         DriverManager.getConnection(url, username, password);
138       return(connection);
139     } catch(ClassNotFoundException JavaDoc cnfe) {
140       // Simplify try/catch blocks of people using this by
141
// throwing only one exception type.
142
throw new SQLException("Can't find class for driver: " +
143                              driver);
144     }
145   }
146
147   public synchronized void free(Connection connection) {
148     busyConnections.removeElement(connection);
149     availableConnections.addElement(connection);
150     // Wake up threads that are waiting for a connection
151
notifyAll();
152
153   }
154
155   public synchronized int totalConnections() {
156     return(availableConnections.size() +
157            busyConnections.size());
158   }
159
160   /** Close all the connections. Use with caution:
161    * be sure no connections are in use before
162    * calling. Note that you are not <I>required</I> to
163    * call this when done with a ConnectionPool, since
164    * connections are guaranteed to be closed when
165    * garbage collected. But this method gives more control
166    * regarding when the connections are closed.
167    */

168
169   public synchronized void closeAllConnections() {
170     closeConnections(availableConnections);
171     availableConnections = new Vector();
172     closeConnections(busyConnections);
173     busyConnections = new Vector();
174   }
175
176   private void closeConnections(Vector connections) {
177     try {
178       for(int i=0; i<connections.size(); i++) {
179         Connection connection =
180           (Connection)connections.elementAt(i);
181         if (!connection.isClosed()) {
182           connection.close();
183         }
184       }
185     } catch(SQLException sqle) {
186       // Ignore errors; garbage collect anyhow
187
}
188   }
189
190   public synchronized String JavaDoc toString() {
191     String JavaDoc info =
192       "ConnectionPool(" + url + "," + username + ")" +
193       ", available=" + availableConnections.size() +
194       ", busy=" + busyConnections.size() +
195       ", max=" + maxConnections;
196     return(info);
197   }
198 }
199
Popular Tags