KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > controller > connection > AbstractPoolConnectionManager


1 /**
2  * Sequoia: Database clustering technology.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
6  * Contact: sequoia@continuent.org
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  * Initial developer(s): Emmanuel Cecchet.
21  * Contributor(s): Mathieu Peltier.
22  */

23
24 package org.continuent.sequoia.controller.connection;
25
26 import java.sql.Connection JavaDoc;
27 import java.sql.SQLException JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.ConcurrentModificationException JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.LinkedList JavaDoc;
32 import java.util.Map JavaDoc;
33
34 import org.continuent.sequoia.common.i18n.Translate;
35
36 /**
37  * This connection manager uses a pool of persistent connections with the
38  * database. The allocation/release policy is implemented by the subclasses
39  * (abstract
40  * {@link org.continuent.sequoia.controller.connection.AbstractConnectionManager#getConnection()}/
41  * {@link org.continuent.sequoia.controller.connection.AbstractConnectionManager#releaseConnection(PooledConnection)}
42  * from
43  * {@link org.continuent.sequoia.controller.connection.AbstractConnectionManager}).
44  *
45  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
46  * @author <a HREF="mailto:Mathieu.Peltier@inrialpes.fr">Mathieu Peltier </a>
47  * @version 1.0
48  */

49 public abstract class AbstractPoolConnectionManager
50     extends AbstractConnectionManager
51 {
52   //
53
// How the code is organized ?
54
//
55
// 1. Member variables
56
// 2. Constructor(s)
57
// 3. Connection handling
58
// 4. Getter/Setter (possibly in alphabetical order)
59
//
60

61   /** Stack of available <code>PooledConnection</code> */
62   protected transient LinkedList JavaDoc freeConnections;
63
64   /**
65    * Pool of currently used connections (<code>Vector</code> type because
66    * synchronisation is needed). Uses <code>PooledConnection</code> objects.
67    */

68   protected transient ArrayList JavaDoc activeConnections;
69
70   /** Size of the connection pool with the real database. */
71   protected int poolSize;
72
73   /*
74    * Constructor(s)
75    */

76
77   /**
78    * Creates a new <code>AbstractPoolConnectionManager</code> instance.
79    *
80    * @param backendUrl URL of the <code>DatabaseBackend</code> owning this
81    * connection manager.
82    * @param backendName name of the <code>DatabaseBackend</code> owning this
83    * connection manager.
84    * @param login backend connection login to be used by this connection
85    * manager.
86    * @param password backend connection password to be used by this connection
87    * manager.
88    * @param driverPath path for driver
89    * @param driverClassName class name for driver
90    * @param poolSize size of the connection pool.
91    */

92   public AbstractPoolConnectionManager(String JavaDoc backendUrl, String JavaDoc backendName,
93       String JavaDoc login, String JavaDoc password, String JavaDoc driverPath, String JavaDoc driverClassName,
94       int poolSize)
95   {
96     super(backendUrl, backendName, login, password, driverPath, driverClassName);
97
98     if (poolSize < 1)
99       throw new IllegalArgumentException JavaDoc(
100           "Illegal value for size of the pool connection manager: " + poolSize);
101
102     this.poolSize = poolSize;
103     this.freeConnections = new LinkedList JavaDoc();
104     this.activeConnections = new ArrayList JavaDoc(poolSize);
105     this.initialized = false;
106
107     if (logger.isDebugEnabled())
108       logger.debug(Translate.get("connection.backend.pool.created",
109           new String JavaDoc[]{backendName, String.valueOf(poolSize)}));
110   }
111
112   /*
113    * Connection handling
114    */

115
116   /**
117    * @see org.continuent.sequoia.controller.connection.AbstractConnectionManager#doConnectionInitialization()
118    */

119   protected synchronized void doConnectionInitialization() throws SQLException JavaDoc
120   {
121     doConnectionInitialization(poolSize);
122     if (idlePersistentConnectionPingInterval > 0)
123     {
124       persistentConnectionPingerThread = new IdlePersistentConnectionsPingerThread(
125           backendName, this);
126       persistentConnectionPingerThread.start();
127       idlePersistentConnectionPingRunning = true;
128     }
129   }
130
131   /**
132    * Initialize initPoolSize connections in the pool.
133    *
134    * @param initPoolSize number of connections to initialize
135    * @throws SQLException if an error occurs
136    */

137   protected synchronized void doConnectionInitialization(int initPoolSize)
138       throws SQLException JavaDoc
139   {
140     if (initialized)
141       throw new SQLException JavaDoc("Connection pool for backend '" + backendUrl
142           + "' already initialized");
143
144     if (initPoolSize > poolSize)
145     {
146       logger.warn(Translate.get("connection.max.poolsize.reached",
147           new String JavaDoc[]{String.valueOf(initPoolSize), String.valueOf(poolSize),
148               String.valueOf(poolSize)}));
149       initPoolSize = poolSize;
150     }
151
152     Connection JavaDoc c = null;
153
154     boolean connectionsAvailable = true;
155     int i = 0;
156     while ((i < initPoolSize) && connectionsAvailable)
157     {
158       c = getConnectionFromDriver();
159
160       if (c == null)
161         connectionsAvailable = false;
162
163       if (!connectionsAvailable)
164       {
165         if (i > 0)
166         {
167           logger.warn(Translate.get("connection.limit.poolsize", i));
168         }
169         else
170         {
171           logger.warn(Translate.get("connection.initialize.pool.failed"));
172           poolSize = 0;
173         }
174       }
175       else
176       {
177         PooledConnection pc = new PooledConnection(c);
178         freeConnections.addLast(pc);
179         i++;
180       }
181     }
182
183     poolSize = i;
184     initialized = true;
185
186     if (poolSize == 0) // Should never happen
187
logger.error(Translate.get("connection.empty.pool"));
188     if (logger.isDebugEnabled())
189       logger.debug(Translate.get("connection.pool.initialized", new String JavaDoc[]{
190           String.valueOf(initPoolSize), backendUrl}));
191
192   }
193
194   /**
195    * @see org.continuent.sequoia.controller.connection.AbstractConnectionManager#doConnectionFinalization()
196    */

197   protected synchronized void doConnectionFinalization() throws SQLException JavaDoc
198   {
199     if (!initialized)
200     {
201       String JavaDoc msg = Translate.get("connection.pool.not.initialized");
202       logger.error(msg);
203       throw new SQLException JavaDoc(msg);
204     }
205
206     PooledConnection c;
207     boolean error = false;
208
209     // Close free connections
210
initialized = false;
211     int freed = 0;
212     while (!freeConnections.isEmpty())
213     {
214       c = (PooledConnection) freeConnections.removeLast();
215       try
216       {
217         c.getConnection().close();
218       }
219       catch (SQLException JavaDoc e)
220       {
221         error = true;
222       }
223       freed++;
224     }
225     if (logger.isInfoEnabled())
226       logger.info(Translate.get("connection.freed.connection", new String JavaDoc[]{
227           String.valueOf(freed), backendUrl}));
228
229     // Close active connections
230
int size = activeConnections.size();
231     if (size > 0)
232     {
233       logger.warn(Translate.get("connection.connections.still.active", size));
234       for (int i = 0; i < size; i++)
235       {
236         c = (PooledConnection) activeConnections.get(i);
237
238         // Try to remove connection from persistent connection map.
239
// This calls for a more evolved data structure such as a "two-way" map.
240
// If somebody closes a persistent connection while we are in the
241
// just retry
242
boolean retry;
243         do
244         {
245           retry = false;
246           try
247           {
248             for (Iterator JavaDoc iter = persistentConnections.entrySet().iterator(); iter
249                 .hasNext();)
250             {
251               Map.Entry JavaDoc element = (Map.Entry JavaDoc) iter.next();
252               if (element.getValue() == c)
253               {
254                 iter.remove();
255               }
256             }
257           }
258           catch (ConcurrentModificationException JavaDoc e)
259           {
260             retry = true;
261           }
262         }
263         while (retry);
264         /*
265          * Closing a connection while it is use can lead to problems.
266          * MySQL can deadlock and Sybase produces NPEs. Either the request
267          * will complete and the Connection will be closed or the
268          */

269         
270 // try
271
// {
272
// c.getConnection().close();
273
// }
274
// catch (SQLException e)
275
// {
276
// error = true;
277
// }
278
}
279     }
280
281     // Clear connections to ensure that the eventually not closed connections
282
// will be closed when the objects will be garbage collected
283
freeConnections.clear();
284     activeConnections.clear();
285     this.notifyAll();
286     System.gc();
287
288     if (error)
289     {
290       String JavaDoc msg = Translate.get("connection.free.connections.failed");
291       logger.error(msg);
292       throw new SQLException JavaDoc(msg);
293     }
294   }
295
296   /**
297    * @see org.continuent.sequoia.controller.connection.AbstractConnectionManager#flagAllConnectionsForRenewal()
298    */

299   public synchronized void flagAllConnectionsForRenewal()
300   {
301     if (!initialized)
302     {
303       String JavaDoc msg = Translate.get("connection.pool.not.initialized");
304       logger.error(msg);
305       throw new RuntimeException JavaDoc(msg);
306     }
307
308     for (Iterator JavaDoc iter = freeConnections.iterator(); iter.hasNext();)
309     {
310       PooledConnection c = (PooledConnection) iter.next();
311       c.setMustBeRenewed(true);
312     }
313
314     for (Iterator JavaDoc iter = activeConnections.iterator(); iter.hasNext();)
315     {
316       PooledConnection c = (PooledConnection) iter.next();
317       c.setMustBeRenewed(true);
318     }
319   }
320
321   /**
322    * @see org.continuent.sequoia.controller.connection.AbstractConnectionManager#getCurrentNumberOfConnections()
323    */

324   public int getCurrentNumberOfConnections()
325   {
326     return poolSize;
327   }
328 }
Popular Tags