KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > proxool > Prototyper


1 /*
2  * This software is released under a licence similar to the Apache Software Licence.
3  * See org.logicalcobwebs.proxool.package.html for details.
4  * The latest version is available at http://proxool.sourceforge.net
5  */

6 package org.logicalcobwebs.proxool;
7
8 import java.sql.Connection JavaDoc;
9 import java.sql.SQLException JavaDoc;
10
11 import org.apache.commons.logging.Log;
12 import org.apache.commons.logging.LogFactory;
13
14 /**
15  * Responsible for prototyping connections for all pools
16  * @version $Revision: 1.14 $, $Date: 2006/03/23 11:44:57 $
17  * @author bill
18  * @author $Author: billhorsman $ (current maintainer)
19  * @since Proxool 0.8
20  */

21 public class Prototyper {
22
23     private ConnectionPool connectionPool;
24
25     private Log log = LogFactory.getLog(Prototyper.class);
26
27     private long connectionCount;
28
29     private final Object JavaDoc lock = new Integer JavaDoc(1);
30
31     private boolean sweepNeeded = true;
32
33     /** This allows us to have a unique ID for each connection */
34     private long nextConnectionId = 1;
35
36     /**
37      * Calling {@link #cancel} will set this to true and stop all
38      * current prototyping immediately
39      */

40     private boolean cancel;
41
42     /**
43      * The number of connections currently being made (actually in
44      * progress)
45      */

46     private int connectionsBeingMade;
47
48     /**
49      * The builder that will create *real* connections for us.
50      * Currently initialized to the default implementation until we fully
51      * support pluggable ConnectionBuilders
52      */

53     private ConnectionBuilderIF connectionBuilder = new DefaultConnectionBuilder();
54     
55     public Prototyper(ConnectionPool connectionPool) {
56         this.connectionPool = connectionPool;
57         this.log = connectionPool.getLog();
58     }
59
60     protected boolean isSweepNeeded() {
61         return sweepNeeded;
62     }
63
64     protected void triggerSweep() {
65         sweepNeeded = true;
66     }
67
68     /**
69      * Trigger prototyping immediately
70      * @return true if something was prototyped
71      */

72     protected boolean sweep() {
73
74         boolean somethingDone = false;
75         try {
76
77             while (!cancel && connectionPool.isConnectionPoolUp()) {
78
79 // if (log.isDebugEnabled()) {
80
// log.debug("Prototyping");
81
// }
82

83                 String JavaDoc reason = null;
84                 if (connectionCount >= getDefinition().getMaximumConnectionCount()) {
85                     // We don't want to make any more that the maximum
86
break;
87                 } else if (connectionCount < getDefinition().getMinimumConnectionCount()) {
88                     reason = "to achieve minimum of " + getDefinition().getMinimumConnectionCount();
89                 } else if (connectionPool.getAvailableConnectionCount() < getDefinition().getPrototypeCount()) {
90                     reason = "to keep " + getDefinition().getPrototypeCount() + " available";
91                 } else {
92                     // Nothing to do
93
break;
94                 }
95
96                 ProxyConnectionIF freshlyBuiltProxyConnection = null;
97                 try {
98                     // If it has been shutdown then we should just stop now.
99
if (!connectionPool.isConnectionPoolUp()) {
100                         break;
101                     }
102                     freshlyBuiltProxyConnection = buildConnection(ConnectionInfoIF.STATUS_AVAILABLE, reason);
103                     somethingDone = true;
104                 } catch (Throwable JavaDoc e) {
105                     log.error("Prototype", e);
106                     // If there's been an exception, perhaps we should stop
107
// prototyping for a while. Otherwise if the database
108
// has problems we end up trying the connection every 2ms
109
// or so and then the log grows pretty fast.
110
break;
111                     // Don't wory, we'll start again the next time the
112
// housekeeping thread runs.
113
}
114                 if (freshlyBuiltProxyConnection == null) {
115                     // That's strange. No double the buildConnection() method logged the
116
// error, but we should have build a connection here.
117
}
118             }
119         } catch (Throwable JavaDoc t) {
120             log.error("Unexpected error", t);
121         }
122
123         return somethingDone;
124     }
125
126     /**
127      * Build a new connection
128      * @param status the initial status it will be created as (this allows us
129      * to create it as {@link ConnectionInfoIF#STATUS_ACTIVE ACTIVE} and avoid
130      * another thread grabbing it before we can)
131      * @param creator for log audit
132      * @return the new connection
133      */

134     protected ProxyConnection buildConnection(int status, String JavaDoc creator) throws SQLException JavaDoc, ProxoolException {
135
136         long id = 0;
137         synchronized (lock) {
138
139             // Check that we are allowed to make another connection
140
if (connectionCount >= getDefinition().getMaximumConnectionCount()) {
141                 throw new ProxoolException("ConnectionCount is " + connectionCount + ". Maximum connection count of "
142                         + getDefinition().getMaximumConnectionCount() + " cannot be exceeded.");
143             }
144
145             checkSimultaneousBuildThrottle();
146
147             connectionsBeingMade++;
148             connectionCount++;
149             id = nextConnectionId++;
150         }
151
152
153         ProxyConnection proxyConnection = null;
154         Connection JavaDoc realConnection = null;
155
156         try {
157             // get a new *real* connection
158
final ConnectionPoolDefinition definition = connectionPool.getDefinition();
159             realConnection = connectionBuilder.buildConnection(definition);
160             
161             // build a proxy around it
162

163             //TODO BRE: the connection builder has made a new connection using the information
164
// supplied in the ConnectionPoolDefinition. That's where it got the URL...
165
// The ProxyConnection is passed the ConnectionPoolDefinition as well so it doesn't
166
// need the url in its constructor...
167
String JavaDoc url = definition.getUrl();
168             proxyConnection = new ProxyConnection(realConnection, id, url, connectionPool, definition, status);
169
170             try {
171                 connectionPool.onBirth(realConnection);
172             } catch (Exception JavaDoc e) {
173                 log.error("Problem during onBirth (ignored)", e);
174             }
175             
176             //TODO BRE: the actual pool of connections is maintained by the ConnectionPool. I'm not
177
// very happy with the idea of letting the Prototyper add the newly build connection
178
// into the pool itself. It should rather be the pool that does it, after it got a new
179
// connection from the Prototyper. This would clearly separate the responsibilities:
180
// ConnectionPool maintains the pool and its integrity, the Prototyper creates new
181
// connections when instructed.
182
boolean added = connectionPool.addProxyConnection(proxyConnection);
183             if (log.isDebugEnabled()) {
184                 StringBuffer JavaDoc out = new StringBuffer JavaDoc(connectionPool.displayStatistics());
185                 out.append(" - Connection #");
186                 out.append(proxyConnection.getId());
187                 if (getDefinition().isVerbose()) {
188                     out.append(" (");
189                     out.append(Integer.toHexString(proxyConnection.hashCode()));
190                     out.append(")");
191                 }
192                 out.append(" created ");
193                 out.append(creator);
194                 out.append(" = ");
195                 out.append(ConnectionPool.getStatusDescription(proxyConnection.getStatus()));
196                 if (getDefinition().isVerbose()) {
197                     out.append(" -> ");
198                     out.append(getDefinition().getUrl());
199                     out.append(" (");
200                     out.append(Integer.toHexString(proxyConnection.getConnection().hashCode()));
201                     out.append(") by thread ");
202                     out.append(Thread.currentThread().getName());
203                 }
204                 log.debug(out);
205                 if (!added) {
206                     out = new StringBuffer JavaDoc(connectionPool.displayStatistics());
207                     out.append(" - Connection #");
208                     out.append(proxyConnection.getId());
209                     out.append(" has been discarded immediately because the definition it was built with is out of date");
210                     log.debug(out);
211                 }
212             }
213             if (!added) {
214                 proxyConnection.reallyClose();
215             }
216
217         } catch (SQLException JavaDoc e) {
218             // log.error(displayStatistics() + " - Couldn't initialise connection #" + proxyConnection.getId() + ": " + e);
219
throw e;
220         } catch (RuntimeException JavaDoc e) {
221             if (log.isDebugEnabled()) {
222                 log.debug("Prototyping problem", e);
223             }
224             throw e;
225         } catch (Throwable JavaDoc t) {
226             if (log.isDebugEnabled()) {
227                 log.debug("Prototyping problem", t);
228             }
229             throw new ProxoolException("Unexpected prototyping problem", t);
230         } finally {
231             synchronized (lock) {
232                 if (proxyConnection == null) {
233                     // If there has been an exception then we won't be using this one and
234
// we need to decrement the counter
235
connectionCount--;
236                 }
237                 connectionsBeingMade--;
238             }
239
240         }
241
242         return proxyConnection;
243     }
244
245     
246     /**
247      * This needs to be called _everytime_ a connection is removed.
248      */

249     protected void connectionRemoved() {
250         connectionCount--;
251     }
252
253     /**
254      * Checks whether we are currently already building too many connections
255      * @throws SQLException if the throttle has been reached
256      */

257     protected void checkSimultaneousBuildThrottle() throws SQLException JavaDoc {
258         // Check we aren't making too many simultaneously
259
if (connectionsBeingMade > getDefinition().getSimultaneousBuildThrottle()) {
260             throw new SQLException JavaDoc("We are already in the process of making " + connectionsBeingMade
261                     + " connections and the number of simultaneous builds has been throttled to "
262                     + getDefinition().getSimultaneousBuildThrottle());
263         }
264     }
265
266     /**
267      * The total number of connections, including those being built right
268      * now
269      * @return connectionCount;
270      */

271     public long getConnectionCount() {
272         return connectionCount;
273     }
274
275     /**
276      * Utility method
277      * @return definition
278      */

279     private ConnectionPoolDefinitionIF getDefinition() {
280         return connectionPool.getDefinition();
281     }
282
283     /**
284      * Cancel all current prototyping
285      */

286     public void cancel() {
287         cancel = true;
288     }
289
290     /**
291      * The alias of the pool we are prototyping for
292      * @return alias
293      */

294     public String JavaDoc getAlias() {
295         return getDefinition().getAlias();
296     }
297
298     /**
299      * Give a quick answer to whether we should attempt to build a connection. This can be quicker
300      * if we are massively overloaded rather than cycling through each connection in the pool to
301      * see if it's free
302      * @throws SQLException if it is a waste of time even trying to get a connaction. Just because this method
303      * doesn't throw an exception it doesn't guarantee that one will be available. There is a slight
304      * risk that we might tell the client to give up when a connection could become available in the next few
305      * milliseconds but our policy is to refuse connections quickly when overloaded.
306      */

307     public void quickRefuse() throws SQLException JavaDoc {
308         if (connectionCount >= getDefinition().getMaximumConnectionCount() && connectionPool.getAvailableConnectionCount() < 1) {
309             throw new SQLException JavaDoc("Couldn't get connection because we are at maximum connection count (" + connectionCount + "/" + getDefinition().getMaximumConnectionCount() + ") and there are none available");
310         }
311     }
312 }
313
314
315 /*
316  Revision history:
317  $Log: Prototyper.java,v $
318  Revision 1.14 2006/03/23 11:44:57 billhorsman
319  More information when quickly refusing
320
321  Revision 1.13 2006/01/18 14:40:01 billhorsman
322  Unbundled Jakarta's Commons Logging.
323
324  Revision 1.12 2006/01/16 23:10:41 billhorsman
325  Doh. /Do/ decrement connectionCount if we didn't make one.
326
327  Revision 1.11 2005/10/02 12:36:30 billhorsman
328  New quickRefuse() method checks whether we are overloaded without checking whole pool for an available connection.
329
330  Revision 1.10 2005/05/04 16:27:54 billhorsman
331  Check to see whether a new connection was really added to the pool.
332
333  Revision 1.9 2004/03/25 22:02:15 brenuart
334  First step towards pluggable ConnectionBuilderIF & ConnectionValidatorIF.
335  Include some minor refactoring that lead to deprecation of some PrototyperController methods.
336
337  Revision 1.7 2003/09/30 18:39:08 billhorsman
338  New test-before-use, test-after-use and fatal-sql-exception-wrapper-class properties.
339
340  Revision 1.6 2003/09/11 10:44:54 billhorsman
341  Catch throwable not just exception during creation of connection
342  (this will catch ClassNotFoundError too)
343
344  Revision 1.5 2003/04/10 08:22:33 billhorsman
345  removed some very frequent debug
346
347  Revision 1.4 2003/03/11 14:51:52 billhorsman
348  more concurrency fixes relating to snapshots
349
350  Revision 1.3 2003/03/10 23:43:10 billhorsman
351  reapplied checkstyle that i'd inadvertently let
352  IntelliJ change...
353
354  Revision 1.2 2003/03/10 15:26:47 billhorsman
355  refactoringn of concurrency stuff (and some import
356  optimisation)
357
358  Revision 1.1 2003/03/05 18:42:33 billhorsman
359  big refactor of prototyping and house keeping to
360  drastically reduce the number of threads when using
361  many pools
362
363  */
Popular Tags