KickJava   Java API By Example, From Geeks To Geeks.

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


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 org.apache.commons.logging.Log;
9 import org.apache.commons.logging.LogFactory;
10 import org.logicalcobwebs.proxool.admin.Admin;
11 import org.logicalcobwebs.proxool.admin.SnapshotIF;
12 import org.logicalcobwebs.proxool.admin.StatisticsIF;
13 import org.logicalcobwebs.proxool.admin.StatisticsListenerIF;
14
15 import java.lang.reflect.Method JavaDoc;
16 import java.sql.Connection JavaDoc;
17 import java.sql.Statement JavaDoc;
18 import java.util.Collection JavaDoc;
19 import java.util.HashMap JavaDoc;
20 import java.util.Map JavaDoc;
21 import java.util.Properties JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.ArrayList JavaDoc;
25
26 /**
27  * <p>This provides some nice-to-have features that can't be provided by the
28  * {@link java.sql.Driver} {@link ProxoolDriver implementation} of java.sql.Driver. Like starting up
29  * a pool before you need a connection. And getting statistical information.</p>
30  *
31  * <p>You need to use this class wisely. It is obviously specfic to proxool so it will
32  * stop you switching to another driver. Consider isolating the code that calls this
33  * class so that you can easily remove it if you have to.</p>
34  *
35  * @version $Revision: 1.85 $, $Date: 2006/11/02 10:00:34 $
36  * @author billhorsman
37  * @author $Author: billhorsman $ (current maintainer)
38  */

39 public class ProxoolFacade {
40
41     private static final Log LOG = LogFactory.getLog(ProxoolFacade.class);
42
43     private static Map JavaDoc configurators = new HashMap JavaDoc();
44
45     private static CompositeProxoolListener compositeProxoolListener = new CompositeProxoolListener();
46
47     private static boolean versionLogged = false;
48
49     /**
50      * This is the thread that has been registered with {@link Runtime} as a
51      * shutdownHook. It is removed during shutdown.
52      */

53     private static Thread JavaDoc shutdownHook;
54
55     /**
56      * If you setthis to false then it us up to you to call shutdown explicitly
57      * @see #shutdown(String, int)
58      */

59     private static boolean shutdownHookEnabled = true;
60
61     /**
62      * Build a ConnectionPool based on this definition and then start it.
63      * @param url defines the delegate driver and delegate url.
64      * @param info the properties used to configure Proxool (and any for the delegate driver too) - optional
65      * @return the alias for this pool (or the full url if no alias is specified)
66      * @throws ProxoolException if anything goes wrong
67      */

68     public static synchronized String JavaDoc registerConnectionPool(String JavaDoc url, Properties JavaDoc info) throws ProxoolException {
69         return registerConnectionPool(url, info, true);
70     }
71
72     /**
73      * Build a ConnectionPool based on this definition and then start it.
74      * @param url defines the delegate driver and delegate url.
75      * @param info the properties used to configure Proxool (and any for the delegate driver too) - optional
76      * @param explicitRegister set to true if we are registering a new pool explicitly, or false
77      * if it's just because we are serving a url that we haven't come across before
78      * @return the alias for this pool (or the full url if no alias is specified)
79      * @throws ProxoolException if anything goes wrong
80      */

81     protected static synchronized String JavaDoc registerConnectionPool(String JavaDoc url, Properties JavaDoc info, boolean explicitRegister) throws ProxoolException {
82         String JavaDoc alias = getAlias(url);
83
84         if (!versionLogged) {
85             versionLogged = true;
86             LOG.info("Proxool " + Version.getVersion());
87         }
88
89         try {
90             Class.forName(ProxoolDriver.class.getName());
91         } catch (ClassNotFoundException JavaDoc e) {
92             LOG.error("Couldn't load " + ProxoolDriver.class.getName());
93         }
94
95         if (!ConnectionPoolManager.getInstance().isPoolExists(alias)) {
96             ConnectionPoolDefinition cpd = new ConnectionPoolDefinition(url, info, explicitRegister);
97             registerConnectionPool(cpd);
98         } else {
99             throw new ProxoolException("Attempt to register duplicate pool called '" + alias + "'");
100         }
101
102         return alias;
103     }
104
105     protected synchronized static void registerConnectionPool(ConnectionPoolDefinition connectionPoolDefinition) throws ProxoolException {
106         // check isPoolExists once more now we are inside synchronized block.
107
if (!ConnectionPoolManager.getInstance().isPoolExists(connectionPoolDefinition.getAlias())) {
108             Properties JavaDoc jndiProperties = extractJndiProperties(connectionPoolDefinition);
109             ConnectionPool connectionPool = ConnectionPoolManager.getInstance().createConnectionPool(connectionPoolDefinition);
110             connectionPool.start();
111             compositeProxoolListener.onRegistration(connectionPoolDefinition, connectionPoolDefinition.getCompleteInfo());
112             if (isConfiguredForJMX(connectionPoolDefinition.getCompleteInfo())) {
113                 registerForJmx(connectionPoolDefinition.getAlias(), connectionPoolDefinition.getCompleteInfo());
114             }
115             if (jndiProperties != null) {
116                 registerDataSource(connectionPoolDefinition.getAlias(), jndiProperties);
117             }
118         } else {
119             LOG.debug("Ignoring duplicate attempt to register " + connectionPoolDefinition.getAlias() + " pool");
120         }
121     }
122
123     /**
124      * With no configurator or properties (using default values)
125      * @see #registerConnectionPool(java.lang.String, java.util.Properties)
126      */

127     public static void registerConnectionPool(String JavaDoc url) throws ProxoolException {
128         registerConnectionPool(url, null);
129     }
130
131     /**
132      * Extracts the pool alias from the url:
133      *
134      * proxool.alias:driver:url -> alias
135      * proxool.alias -> alias
136      *
137      * @return the alias defined within the url
138      * @throws ProxoolException if we couldn't find the alias
139      */

140     protected static String JavaDoc getAlias(String JavaDoc url) throws ProxoolException {
141         String JavaDoc alias = null;
142         final String JavaDoc prefix = ProxoolConstants.PROXOOL + ProxoolConstants.ALIAS_DELIMITER;
143
144         // Check that the prefix is there
145
if (url.startsWith(prefix)) {
146
147             // Check for the alias
148
int endOfPrefix = url.indexOf(ProxoolConstants.URL_DELIMITER);
149
150             if (endOfPrefix > -1) {
151                 alias = url.substring(prefix.length(), endOfPrefix);
152             } else {
153                 alias = url.substring(prefix.length());
154             }
155         }
156
157         // Check we found it.
158
if (alias == null || alias.length() == 0) {
159             throw new ProxoolException("The URL '" + url + "' is not in the correct form. It should be: 'proxool.alias:driver:url'");
160         }
161
162         return alias;
163     }
164
165     /**
166      * Remove a connection pool. Kills all the connections. Resets everything.
167      * @param finalizer the name of the thread requesting shutdown (for logging)
168      * @param connectionPool the pool to remove
169      * @param delay the time to wait for connections to become inactive before killing it (milliseconds)
170      */

171     private static void removeConnectionPool(String JavaDoc finalizer, ConnectionPool connectionPool, int delay) {
172         final String JavaDoc alias = connectionPool.getDefinition().getAlias();
173         if (connectionPool != null) {
174             try {
175                 compositeProxoolListener.onShutdown(alias);
176                 connectionPool.shutdown(delay, finalizer);
177             } catch (Throwable JavaDoc t) {
178                 LOG.error("Problem trying to shutdown '" + alias + "' connection pool", t);
179             }
180         }
181         connectionPool = null;
182     }
183
184     /**
185      * Remove a connection pool. Kills all the connections. Resets everything.
186      * @param alias the pool to remove
187      * @param delay the time to wait for connections to become inactive before killing it (milliseconds)
188      * @throws ProxoolException if we couldn't find the pool
189      */

190     public static void removeConnectionPool(String JavaDoc alias, int delay) throws ProxoolException {
191         removeConnectionPool(Thread.currentThread().getName(), ConnectionPoolManager.getInstance().getConnectionPool(alias), delay);
192     }
193
194     /**
195      * Removes all connection pools. Kills all the connections. Resets everything.
196      * @param delay the time to wait for connections to become inactive before killing it (milliseconds)
197      * @deprecated use the better named {@link #shutdown(int) shutdown()} instead.
198      */

199     public static void removeAllConnectionPools(int delay) {
200         shutdown(Thread.currentThread().getName(), delay);
201     }
202
203     /**
204      * Removes all connection pools. Kills all the connections. Resets everything.
205      * Like {@link #shutdown(java.lang.String, int)} but passes the current thread name
206      * and a delay of zero.
207      */

208     public static void shutdown() {
209         shutdown(Thread.currentThread().getName(), 0);
210     }
211
212     /**
213      * Removes all connection pools. Kills all the connections. Resets everything.
214      * Like {@link #shutdown(java.lang.String, int)} but passes the current thread name.
215      * @param delay the time to wait for connections to become inactive before killing it (milliseconds)
216      */

217     public static void shutdown(int delay) {
218         shutdown(Thread.currentThread().getName(), delay);
219     }
220
221     /**
222      * Removes all connection pools. Kills all the connections. Resets everything.
223      * @param finalizer used to identify who is causing the pools to be removed (helps logging)
224      * @param delay the time to wait for connections to become inactive before killing it (milliseconds)
225      */

226     protected static void shutdown(String JavaDoc finalizer, int delay) {
227
228         ConnectionPool[] cps = ConnectionPoolManager.getInstance().getConnectionPools();
229         for (int i = 0; i < cps.length; i++) {
230             removeConnectionPool(finalizer, cps[i], delay);
231         }
232
233         // If a shutdown hook was registered then remove it
234
try {
235             if (shutdownHook != null) {
236                 ShutdownHook.remove(shutdownHook);
237             }
238         } catch (Throwable JavaDoc t) {
239             if (LOG.isDebugEnabled()) {
240                 LOG.debug("Unanticipated error during removal of ShutdownHook. Ignoring it.", t);
241             }
242         }
243
244         // Stop threads
245
PrototyperController.shutdown();
246         HouseKeeperController.shutdown();
247
248     }
249
250     /**
251      * If you call this then you'll have to call shutdown explicitly
252      * @see #shutdown(String, int)
253      */

254     public static void disableShutdownHook() {
255         ProxoolFacade.shutdownHookEnabled = false;
256     }
257
258     /**
259      * Call this if you change your mind about {@link #disableShutdownHook() disabling} it.
260      * The default behaviour is to have it enabled so unless you have disabled it then
261      * there's nothing to do.
262      */

263     public static void enableShutdownHook() {
264         ProxoolFacade.shutdownHookEnabled = true;
265     }
266
267     /**
268      * Whether the {@link ShutdownHook} should do anything.
269      * @see #disableShutdownHook()
270      * @see #enableShutdownHook()
271      * @return true if the shutdown hook should clean up
272      */

273     public static boolean isShutdownHookEnabled() {
274         return shutdownHookEnabled;
275     }
276
277     /**
278      * Like {@link #removeConnectionPool(java.lang.String, int)} but uses no delay. (Kills
279      * everything as quickly as possible).
280      * @param alias to identify the pool
281      * @throws ProxoolException if we couldn't find the pool
282      */

283     public static void removeConnectionPool(String JavaDoc alias) throws ProxoolException {
284         removeConnectionPool(alias, 0);
285     }
286
287     /**
288      * Get real-time statistical information about how a pool is performing.
289      * @param alias to identify the pool
290      * @return the statistics
291      * @throws ProxoolException if we couldn't find the pool
292      * @deprecated use {@link #getSnapshot}
293      */

294     public static ConnectionPoolStatisticsIF getConnectionPoolStatistics(String JavaDoc alias) throws ProxoolException {
295         return ConnectionPoolManager.getInstance().getConnectionPool(alias);
296     }
297
298     /**
299      * Get real-time statistical information about how a pool is performing.
300      * and extract the information piece by piece.
301      * @param alias to identify the pool
302      * @return a horrible string describing the statistics
303      * @throws ProxoolException if we couldn't find the pool
304      * @deprecated use {@link #getSnapshot}
305      */

306     public static String JavaDoc getConnectionPoolStatisticsDump(String JavaDoc alias) throws ProxoolException {
307         return ConnectionPoolManager.getInstance().getConnectionPool(alias).displayStatistics();
308     }
309
310     /**
311      * Get the definition of a pool.
312      * @param alias identifies the pool
313      * @throws ProxoolException if we couldn't find the pool
314      */

315     public static ConnectionPoolDefinitionIF getConnectionPoolDefinition(String JavaDoc alias) throws ProxoolException {
316         return ConnectionPoolManager.getInstance().getConnectionPool(alias).getDefinition();
317     }
318
319     /**
320      * Get details on each connection within the pool. This can tell you which ones are active, how long they have
321      * been active, etc.
322      * @param alias identifies the pool
323      * @return a collection of {@link ConnectionInfoIF ConnectionInfoIFs}
324      * @throws ProxoolException if we couldn't find the pool
325      * @deprecated use {@link #getSnapshot(java.lang.String, boolean) snapshot} instead.
326      */

327     public static Collection JavaDoc getConnectionInfos(String JavaDoc alias) throws ProxoolException {
328         return ConnectionPoolManager.getInstance().getConnectionPool(alias).getConnectionInfos();
329     }
330
331     /**
332      * Kill all connections in a pool. The pool continues to work however, and new connections will be
333      * made as required.
334      * @param alias the pool containing the connection
335      * @param merciful if true will only kill connections that aren't active
336      * @throws ProxoolException if we couldn't find the pool
337      * @deprecated use {@link #killAllConnections(java.lang.String, java.lang.String, boolean) alternative}
338      * to provide better auditing in log
339      */

340     public static void killAllConnections(String JavaDoc alias, boolean merciful) throws ProxoolException {
341         killAllConnections(alias, "of thread " + Thread.currentThread().getName(), merciful);
342     }
343
344     /**
345      * Kill all connections in a pool. The pool continues to work however, and new connections will be
346      * made as required.
347      * @param alias the pool containing the connection
348      * @param reason provides audit in log of why connections were killed
349      * @param merciful if true will only kill connections that aren't active
350      * @throws ProxoolException if we couldn't find the pool
351      */

352     public static void killAllConnections(String JavaDoc alias, String JavaDoc reason, boolean merciful) throws ProxoolException {
353         ConnectionPoolManager.getInstance().getConnectionPool(alias).expireAllConnections(reason, merciful);
354     }
355
356     /**
357      * Like {@link #killAllConnections} but defaults to merciful.
358      * @param alias to identify the pool
359      * @throws ProxoolException if we couldn't find the pool
360      * @deprecated use {@link #killAllConnections(java.lang.String, java.lang.String) alternative}
361      * to provide better auditing in log
362      */

363     public static void killAllConnections(String JavaDoc alias) throws ProxoolException {
364         killAllConnections(alias, "of thread " + Thread.currentThread().getName(), MERCIFUL);
365     }
366
367     /**
368      * Like {@link #killAllConnections} but defaults to merciful.
369      * @param alias to identify the pool
370      * @param reason provides audit in log of why connections were killed
371      * @throws ProxoolException if we couldn't find the pool
372      */

373     public static void killAllConnections(String JavaDoc alias, String JavaDoc reason) throws ProxoolException {
374         killAllConnections(alias, reason, MERCIFUL);
375     }
376
377     /**
378      * Kill a single connection
379      * @param alias the pool containing the connection
380      * @param id the id of the specific connection
381      * @param merciful if true will only kill connections that aren't active
382      * @return true if the connection was killed, or false if it couldn't be found.
383      * @throws ProxoolException if we couldn't find the pool
384      */

385     public static boolean killConnecton(String JavaDoc alias, long id, boolean merciful) throws ProxoolException {
386         // Let's be explicit about what we're doing here
387
boolean forceExpiry = !merciful;
388         return ConnectionPoolManager.getInstance().getConnectionPool(alias).expireConnection(id, forceExpiry);
389     }
390
391     /**
392      * Kill a single connection
393      * @param connection the connection to kill
394      * @param merciful if true will only kill connections that aren't active
395      * @return true if the connection was killed, or false if it couldn't be found.
396      * @throws ProxoolException if we didn't recognise the connection
397      */

398     public static boolean killConnecton(Connection JavaDoc connection, boolean merciful) throws ProxoolException {
399         WrappedConnection wrappedConnection = ProxyFactory.getWrappedConnection(connection);
400         if (wrappedConnection != null) {
401             long id = wrappedConnection.getId();
402             String JavaDoc alias = wrappedConnection.getAlias();
403             return killConnecton(alias, id, merciful);
404         } else {
405             throw new ProxoolException("Attempt to kill unrecognised exception " + connection);
406         }
407     }
408
409     /**
410      * Add a listener that gets called everytime a global Proxool event ocours.
411      * @param proxoolListener the listener to add.
412      */

413     public static void addProxoolListener(ProxoolListenerIF proxoolListener) {
414         compositeProxoolListener.addListener(proxoolListener);
415     }
416
417     /**
418      * Remove a registered <code>ProxoolListenerIF</code>.
419      * @param proxoolListener the listener to remove.
420      * @return whether the listener was found or removed or not.
421      */

422     public static boolean removeProxoolListener(ProxoolListenerIF proxoolListener) {
423         return compositeProxoolListener.removeListener(proxoolListener);
424     }
425
426     /**
427      * @deprecated use {@link #addStateListener(String, StateListenerIF)} instead.
428      */

429     public static void setStateListener(String JavaDoc alias, StateListenerIF stateListener) throws ProxoolException {
430         addStateListener(alias, stateListener);
431     }
432
433     /**
434      * Add a listener that monitors the change of state of the pool (quiet, busy, overloaded, or down)
435      * @param alias identifies the pool
436      * @param stateListener the new listener
437      * @throws ProxoolException if we couldn't find the pool
438      */

439     public static void addStateListener(String JavaDoc alias, StateListenerIF stateListener) throws ProxoolException {
440         ConnectionPool cp = ConnectionPoolManager.getInstance().getConnectionPool(alias);
441         cp.addStateListener(stateListener);
442     }
443
444     /**
445      * Remove a listener that monitors the change of state of the pool (quiet, busy, overloaded, or down)
446      * @param alias identifies the pool
447      * @param stateListener the listener to be removed.
448      * @throws ProxoolException if we couldn't find the pool
449      * @return wether the listnener was found and removed or not.
450      */

451     public boolean removeStateListener(String JavaDoc alias, StateListenerIF stateListener) throws ProxoolException {
452         ConnectionPool cp = ConnectionPoolManager.getInstance().getConnectionPool(alias);
453         return cp.removeStateListener(stateListener);
454     }
455
456     /**
457      * @deprecated use {@link #addConnectionListener(String, ConnectionListenerIF)} instead.
458      */

459     public static void setConnectionListener(String JavaDoc alias, ConnectionListenerIF connectionListener) throws ProxoolException {
460         addConnectionListener(alias, connectionListener);
461     }
462
463     /**
464      * Add a listener that monitors each time a connection is made or destroyed.
465      * @param alias identifies the pool
466      * @param connectionListener the new listener
467      * @throws ProxoolException if we couldn't find the pool
468      */

469     public static void addConnectionListener(String JavaDoc alias, ConnectionListenerIF connectionListener) throws ProxoolException {
470         ConnectionPool cp = ConnectionPoolManager.getInstance().getConnectionPool(alias);
471         cp.addConnectionListener(connectionListener);
472     }
473
474     /**
475      * Remove a listener that monitors each time a connection is made or destroyed.
476      * @param alias identifies the pool
477      * @param connectionListener the listener to be removed
478      * @throws ProxoolException if we couldn't find the pool
479      * @return wether the listnener was found and removed or not.
480      */

481     public static boolean removeConnectionListener(String JavaDoc alias, ConnectionListenerIF connectionListener) throws ProxoolException {
482         ConnectionPool cp = ConnectionPoolManager.getInstance().getConnectionPool(alias);
483         return cp.removeConnectionListener(connectionListener);
484     }
485
486     /**
487      * @deprecated use {@link #addConfigurationListener(String, ConfigurationListenerIF)} instead.
488      */

489     public static void setConfigurationListener(String JavaDoc alias, ConfigurationListenerIF configurationListener) throws ProxoolException {
490         addConfigurationListener(alias, configurationListener);
491     }
492
493     /**
494      * Adds a listener that gets called everytime the configuration changes.
495      * @param alias identifies the pool
496      * @param configurationListener the new listener
497      * @throws ProxoolException if we couldn't find the pool
498      */

499     public static void addConfigurationListener(String JavaDoc alias, ConfigurationListenerIF configurationListener) throws ProxoolException {
500         if (ConnectionPoolManager.getInstance().isPoolExists(alias)) {
501             CompositeConfigurationListener compositeConfigurationListener = (CompositeConfigurationListener)
502                     configurators.get(alias);
503             if (compositeConfigurationListener == null) {
504                 compositeConfigurationListener = new CompositeConfigurationListener();
505                 configurators.put(alias, compositeConfigurationListener);
506             }
507             compositeConfigurationListener.addListener(configurationListener);
508         } else {
509             throw new ProxoolException(ConnectionPoolManager.getInstance().getKnownPools(alias));
510         }
511     }
512
513     /**
514      * Broadcast a configuration change
515      * @param alias identifies the pool
516      * @param connectionPoolDefinition the definition
517      * @param completeInfo all properties
518      * @param changedInfo only changed properties (since the last
519      * time this method was called)
520      */

521     protected static void definitionUpdated(String JavaDoc alias, ConnectionPoolDefinitionIF connectionPoolDefinition,
522                                             Properties JavaDoc completeInfo, Properties JavaDoc changedInfo) {
523         CompositeConfigurationListener ccl = (CompositeConfigurationListener) configurators.get(alias);
524         if (ccl != null) {
525             ccl.definitionUpdated(connectionPoolDefinition, completeInfo, changedInfo);
526         }
527     }
528
529     /**
530      * Remove a listener that gets called everytime the configuration changes.
531      * @param alias identifies the pool.
532      * @param configurationListener the listener to be removed.
533      * @throws ProxoolException if we couldn't find the pool
534      * @return wether the listnener was found and removed or not.
535      *
536      */

537     public static boolean removeConfigurationListener(String JavaDoc alias, ConfigurationListenerIF configurationListener) throws ProxoolException {
538         boolean removed = false;
539         if (ConnectionPoolManager.getInstance().isPoolExists(alias)) {
540             CompositeConfigurationListener compositeConfigurationListener = (CompositeConfigurationListener)
541                     configurators.get(alias);
542             if (compositeConfigurationListener != null) {
543                 removed = compositeConfigurationListener.removeListener(configurationListener);
544             }
545         } else {
546             throw new ProxoolException(ConnectionPoolManager.getInstance().getKnownPools(alias));
547         }
548         return removed;
549     }
550
551     /**
552      * @see #killAllConnections(java.lang.String)
553      */

554     private static final boolean MERCIFUL = true;
555
556     /**
557      * Redefine the behaviour of the pool. All existing properties (for Proxool
558      * and the delegate driver are reset to their default) and reapplied
559      * based on the parameters sent here.
560      *
561      * @param url the url that defines the pool (or the abbreviated ""proxool.alias")
562      * @param info the new properties
563      * @see #updateConnectionPool
564      */

565     public static void redefineConnectionPool(String JavaDoc url, Properties JavaDoc info) throws ProxoolException {
566         String JavaDoc alias = getAlias(url);
567         ConnectionPool cp = ConnectionPoolManager.getInstance().getConnectionPool(alias);
568         try {
569             // Clone the old one
570
ConnectionPoolDefinition cpd = (ConnectionPoolDefinition) cp.getDefinition().clone();
571             cpd.redefine(url, info);
572             cp.setDefinition(cpd);
573         } catch (CloneNotSupportedException JavaDoc e) {
574             throw new ProxoolException("Funny, why couldn't we clone a definition?", e);
575         }
576     }
577
578
579     /**
580      * Update the behaviour of the pool. Only properties that are defined here are overwritten. That is, properties
581      * that were defined before but are not mentioned here are retained.
582      *
583      * @param url the url that defines the pool (or the abbreviated ""proxool.alias")
584      * @param info the new properties
585      * @see #redefineConnectionPool
586      */

587     public static void updateConnectionPool(String JavaDoc url, Properties JavaDoc info) throws ProxoolException {
588         String JavaDoc alias = getAlias(url);
589         ConnectionPool cp = ConnectionPoolManager.getInstance().getConnectionPool(alias);
590         try {
591             // Clone the old one
592
ConnectionPoolDefinition cpd = (ConnectionPoolDefinition) cp.getDefinition().clone();
593             cpd.update(url, info);
594             cp.setDefinition(cpd);
595         } catch (CloneNotSupportedException JavaDoc e) {
596             throw new ProxoolException("Funny, why couldn't we clone a definition?", e);
597         }
598     }
599
600     protected void finalize() throws Throwable JavaDoc {
601         super.finalize();
602         LOG.debug("Finalising");
603     }
604
605     /**
606      * Returns the driver provided statement that Proxool wraps up before it gives it to you.
607      * @return delegate statement
608      * @deprecated Just cast the statement that you are given into the driver specific one.
609      */

610     public static Statement JavaDoc getDelegateStatement(Statement JavaDoc statement) throws ProxoolException {
611         try {
612             return ProxyFactory.getDelegateStatement(statement);
613         } catch (IllegalArgumentException JavaDoc e) {
614             throw new ProxoolException("Statement argument is not one provided by Proxool (it's a " + statement.getClass() + ")");
615         }
616     }
617
618     /**
619      * Returns the driver provided connection that Proxool wraps up before it gives it to you.
620      * @return delegate connection
621      * @deprecated Just cast the connection that you are given into the driver specific one.
622      */

623     public static Connection JavaDoc getDelegateConnection(Connection JavaDoc connection) throws ProxoolException {
624         try {
625             return ProxyFactory.getDelegateConnection(connection);
626         } catch (IllegalArgumentException JavaDoc e) {
627             throw new ProxoolException("Connection argument is not one provided by Proxool (it's a " + connection.getClass() + ")");
628         }
629     }
630
631     /**
632      * Get the connection ID for a connection
633      * @param connection the connection that was served
634      * @return the ID
635      * @throws ProxoolException if the connection wasn't recognised.
636      */

637     public static long getId(Connection JavaDoc connection) throws ProxoolException {
638         try {
639             return ProxyFactory.getWrappedConnection(connection).getId();
640         } catch (NullPointerException JavaDoc e) {
641             throw new ProxoolException("Connection argument is not one provided by Proxool (it's a " + connection.getClass() + ")");
642         } catch (IllegalArgumentException JavaDoc e) {
643             throw new ProxoolException("Connection argument is not one provided by Proxool (it's a " + connection.getClass() + ")");
644         }
645     }
646
647     /**
648      * Get the alias for the connection pool that served a connection
649      * @param connection the connection that was served
650      * @return the alias
651      * @throws ProxoolException if the connection wasn't recognised.
652      */

653     public static String JavaDoc getAlias(Connection JavaDoc connection) throws ProxoolException {
654         try {
655             return ProxyFactory.getWrappedConnection(connection).getAlias();
656         } catch (NullPointerException JavaDoc e) {
657             throw new ProxoolException("Connection argument is not one provided by Proxool (it's a " + connection.getClass() + ")");
658         } catch (IllegalArgumentException JavaDoc e) {
659             throw new ProxoolException("Connection argument is not one provided by Proxool (it's a " + connection.getClass() + ")");
660         }
661     }
662
663     /**
664      * Get a list of all the registered pools
665      * @return an array of aliases
666      * @since Proxool 0.7
667      */

668     public static String JavaDoc[] getAliases() {
669         return ConnectionPoolManager.getInstance().getConnectionPoolNames();
670     }
671
672     /**
673      * Get a particular set of performance statistics for this pool
674      * @param alias identifies the pool
675      * @param token identifies which set, as defined in the configuration (see {@link ConnectionPoolDefinitionIF#getStatistics definition})
676      * @return a sample containing the statistics
677      * @throws ProxoolException if we couldn't find the pool
678      */

679     public static StatisticsIF getStatistics(String JavaDoc alias, String JavaDoc token) throws ProxoolException {
680         return ConnectionPoolManager.getInstance().getConnectionPool(alias).getAdmin().getStatistics(token);
681     }
682
683     /**
684      * Get all the lastest performance statistics for this pool
685      * @param alias identifies the pool
686      * @return a sample containing the statistics, or a zero length array if there none
687      * @throws ProxoolException if we couldn't find the pool
688      */

689     public static StatisticsIF[] getStatistics(String JavaDoc alias) throws ProxoolException {
690         final Admin monitor = ConnectionPoolManager.getInstance().getConnectionPool(alias).getAdmin();
691         if (monitor != null) {
692             return monitor.getStatistics();
693         } else {
694             return new StatisticsIF[0];
695         }
696     }
697
698     /**
699      * Add a listener that receives statistics as they are produced
700      * @param statisticsListener the new listener
701      * @throws ProxoolException if the pool couldn't be found
702      */

703     public static void addStatisticsListener(String JavaDoc alias, StatisticsListenerIF statisticsListener) throws ProxoolException {
704         // TODO investigate what happens if we add a statistics monitor after we register a listener
705
final Admin monitor = ConnectionPoolManager.getInstance().getConnectionPool(alias).getAdmin();
706         if (monitor != null) {
707             monitor.addStatisticsListener(statisticsListener);
708         } else {
709             throw new ProxoolException("Statistics are switched off, your can't add a listener");
710         }
711     }
712
713     /**
714      * Gives a snapshot of what the pool is doing
715      * @param alias identifies the pool
716      * @param detail if true then include detail of each connection. Note it you ask for
717      * detail then the pool must necessarily be locked for the duration it takes to gather
718      * the information (which isn't very long). You probably shouldn't do it that often (like
719      * not every second or something). Being locked means that connections cannot be
720      * served or returned (it doesn't mean that they can't be active).
721      * @return the current status of the pool
722      * @throws ProxoolException if we couldn't find the pool
723      */

724     public static SnapshotIF getSnapshot(String JavaDoc alias, boolean detail) throws ProxoolException {
725         SnapshotIF snapshot = null;
726         ConnectionPool cp = ConnectionPoolManager.getInstance().getConnectionPool(alias);
727
728         if (detail) {
729             try {
730                 // Only try for 10 seconds!
731
long start = System.currentTimeMillis();
732                 if (cp.attemptConnectionStatusReadLock(10000)) {
733                     snapshot = Admin.getSnapshot(cp, cp.getDefinition(), cp.getConnectionInfos());
734                 } else {
735                     LOG.warn("Give up waiting for detailed snapshot after " + (System.currentTimeMillis() - start) + " milliseconds. Serving standard snapshot instead.");
736                 }
737             } finally {
738                 cp.releaseConnectionStatusReadLock();
739             }
740         }
741         if (snapshot == null) {
742             snapshot = Admin.getSnapshot(cp, cp.getDefinition(), null);
743         }
744
745         return snapshot;
746     }
747
748     /**
749      * Calls {@link #getSnapshot(java.lang.String, boolean) getSnapshot}
750      * using false for the detail parameter.
751      * @see #getSnapshot(java.lang.String, boolean)
752      */

753     public static SnapshotIF getSnapshot(String JavaDoc alias) throws ProxoolException {
754         return getSnapshot(alias, false);
755     }
756
757     // all jmx operations are done through reflection
758
// to avoid making the facade dependant on the JMX classes
759
private static boolean registerForJmx(String JavaDoc alias, Properties JavaDoc properties) {
760         boolean success = false;
761         try {
762             Class JavaDoc jmxHelperClass = Class.forName("org.logicalcobwebs.proxool.admin.jmx.ProxoolJMXHelper");
763             Method JavaDoc registerMethod = jmxHelperClass.getDeclaredMethod("registerPool", new Class JavaDoc[]{String JavaDoc.class, Properties JavaDoc.class});
764             registerMethod.invoke(null, new Object JavaDoc[]{alias, properties});
765             success = true;
766         } catch (Exception JavaDoc e) {
767             LOG.error("JMX registration of " + alias + " pool failed.", e);
768         }
769         return success;
770     }
771
772     // all JNDI operations are done through reflection
773
// to avoid making the facade dependant on the JNDI classes
774
private static boolean registerDataSource(String JavaDoc alias, Properties JavaDoc jndiProperties) {
775         boolean success = false;
776         try {
777             Class JavaDoc jndiHelperClass = Class.forName("org.logicalcobwebs.proxool.admin.jndi.ProxoolJNDIHelper");
778             Method JavaDoc registerMethod = jndiHelperClass.getDeclaredMethod("registerDatasource", new Class JavaDoc[]{String JavaDoc.class,
779                 Properties JavaDoc.class});
780             registerMethod.invoke(null, new Object JavaDoc[]{alias, jndiProperties});
781             success = true;
782         } catch (Exception JavaDoc e) {
783             LOG.error("JNDI DataSource binding of " + alias + " pool failed.", e);
784         }
785         return success;
786     }
787
788     /**
789      * Get the JNDI properties for the given pool definition if it is configured for JNDI registration.
790      * Will remove generic JNDI properties from the delegate properties so that they will not be passed to the
791      * delegate driver.
792      * @param connectionPoolDefinition the pool definition to get the eventual JNDI configuration from.
793      * @return the JNDI properties, or <code>null</code> if the given definition was not configured for JNDI.
794      */

795     private static Properties JavaDoc extractJndiProperties(ConnectionPoolDefinition connectionPoolDefinition) {
796         if (connectionPoolDefinition.getJndiName() == null) {
797             return null;
798         }
799         Properties JavaDoc jndiProperties = new Properties JavaDoc();
800         jndiProperties.setProperty(ProxoolConstants.JNDI_NAME, connectionPoolDefinition.getJndiName());
801         if (connectionPoolDefinition.getDelegateProperties() != null) {
802             Properties JavaDoc delegateProperties = connectionPoolDefinition.getDelegateProperties();
803             // we must retrieve all the relevant property names before removing them from
804
// the given properties to avoid ConcurrentModificationException
805
String JavaDoc propertyName = null;
806             List JavaDoc propertyNamesList = new ArrayList JavaDoc(10);
807             Iterator JavaDoc keySetIterator = delegateProperties.keySet().iterator();
808             while (keySetIterator.hasNext()) {
809                 propertyName = (String JavaDoc) keySetIterator.next();
810                 if (propertyName.startsWith(ProxoolConstants.JNDI_PROPERTY_PREFIX)) {
811                     propertyNamesList.add(propertyName);
812                 }
813             }
814             for (int i = 0; i < propertyNamesList.size(); i++) {
815                 propertyName = (String JavaDoc) propertyNamesList.get(i);
816                 if (propertyName.startsWith(ProxoolConstants.JNDI_PROPERTY_PREFIX)) {
817                     jndiProperties.setProperty(propertyName.substring(ProxoolConstants.JNDI_PROPERTY_PREFIX.length()),
818                         (String JavaDoc) delegateProperties.getProperty(propertyName));
819                     delegateProperties.remove(propertyName);
820                 }
821             }
822         }
823         return jndiProperties;
824     }
825
826     /**
827      * Get wether the given pool properties contains configuration for JMX instrumentation of the pool.
828      * @param poolProperties the properties to check for JMX configuration.
829      * @return wether the given pool properties contains configuration for JMX instrumentation or not.
830      */

831     private static boolean isConfiguredForJMX(Properties JavaDoc poolProperties) {
832         final String JavaDoc jmxProperty = poolProperties.getProperty(ProxoolConstants.JMX_PROPERTY);
833         if (jmxProperty != null && jmxProperty.equalsIgnoreCase("true")) {
834             return true;
835         } else {
836             return false;
837         }
838     }
839
840     /**
841      * By remembering the most recent {@link ShutdownHook} ProxoolFacade
842      * will know to disable it when it is {@link #shutdown}. It will gracefully
843      * cope with the fact that it may be shutting down by the request of the
844      * sutdownHook. If you don't do this and do several "hot deploys" then you
845      * end up with a series of shutdown hooks. We only every want one.
846      * @param t the thread that will be run as a shutdown hook
847      * @see ShutdownHook
848      */

849     protected static void setShutdownHook(Thread JavaDoc t) {
850         shutdownHook = t;
851     }
852 }
853
854 /*
855  Revision history:
856  $Log: ProxoolFacade.java,v $
857  Revision 1.85 2006/11/02 10:00:34 billhorsman
858  Added ProxoolFacade.disableShutdownHook.
859
860  Revision 1.84 2006/01/18 14:40:01 billhorsman
861  Unbundled Jakarta's Commons Logging.
862
863  Revision 1.83 2005/09/26 09:54:14 billhorsman
864  Avoid suspected deadlock when getting a detailed snapshot. Only attempt to get the concurrent lock for 10 seconds before giving up.
865
866  Revision 1.82 2005/05/04 16:32:31 billhorsman
867  Clone the definition when redefining or updating the pool.
868
869  Revision 1.81 2004/09/29 15:43:25 billhorsman
870  Recheck isPoolExists inside synchronized registerConnectionPool method. Credit Juergen Hoeller.
871
872  Revision 1.80 2004/06/02 20:47:05 billhorsman
873  Override shutdown with a zero-parameter version for Spring integration.
874
875  Revision 1.79 2004/03/26 15:58:56 billhorsman
876  Fixes to ensure that house keeper and prototyper threads finish after shutdown.
877
878  Revision 1.78 2004/03/23 21:25:54 billhorsman
879  Added getAlias() call.
880
881  Revision 1.77 2004/03/23 21:19:45 billhorsman
882  Added disposable wrapper to proxied connection. And made proxied objects implement delegate interfaces too.
883
884  Revision 1.76 2004/03/15 02:45:19 chr32
885  Added handling of Proxool managed JNDI DataSources.
886
887  Revision 1.75 2004/02/12 12:54:49 billhorsman
888  Fix merciful/forceExpiry confusion
889
890  Revision 1.74 2003/10/30 00:16:13 billhorsman
891  Throw a friendlier exception if you try and add a statistics listener to a pool with no statistics
892
893  Revision 1.73 2003/10/16 18:52:35 billhorsman
894  Fixed a bug: the redefine() method was actually calling the update() method. Also, added checks to make the
895  "Attempt to use a pool with incomplete definition" exception a bit more descriptive. It's often because you
896  are referring to an unregistered pool simply by using an alias.
897
898  Revision 1.72 2003/09/07 22:09:21 billhorsman
899  Remove any registered ShutdownHooks during shutdown.
900
901  Revision 1.71 2003/08/30 14:54:04 billhorsman
902  Checkstyle
903
904  Revision 1.70 2003/08/28 10:55:49 billhorsman
905  comment out JNDI stuff for now
906
907  Revision 1.69 2003/08/27 18:03:20 billhorsman
908  added new getDelegateConnection() method
909
910  Revision 1.68 2003/07/23 12:38:50 billhorsman
911  some fixes, but more to come
912
913  Revision 1.67 2003/07/23 06:54:48 billhorsman
914  draft JNDI changes (shouldn't effect normal operation)
915
916  Revision 1.66 2003/04/10 21:49:34 billhorsman
917  refactored registration slightly to allow DataSource access
918
919  Revision 1.65 2003/03/11 14:51:53 billhorsman
920  more concurrency fixes relating to snapshots
921
922  Revision 1.64 2003/03/10 15:26:49 billhorsman
923  refactoringn of concurrency stuff (and some import
924  optimisation)
925
926  Revision 1.63 2003/03/03 11:11:58 billhorsman
927  fixed licence
928
929  Revision 1.62 2003/02/28 10:42:59 billhorsman
930  ConnectionPoolManager now passes ProxoolFacade an
931  array of ConnectionPools rather than a Collection
932  to avoid a ConcurrentModificationException during
933  shutdown.
934
935  Revision 1.61 2003/02/27 17:19:18 billhorsman
936  new overloaded getSnapshot method
937
938  Revision 1.60 2003/02/26 16:05:53 billhorsman
939  widespread changes caused by refactoring the way we
940  update and redefine pool definitions.
941
942  Revision 1.59 2003/02/24 18:03:24 chr32
943  Added JMX operations.
944
945  Revision 1.58 2003/02/24 01:15:33 chr32
946  Added support for ProxoolListenerIF.
947
948  Revision 1.57 2003/02/19 23:46:10 billhorsman
949  renamed monitor package to admin
950
951  Revision 1.56 2003/02/19 13:48:28 chr32
952  Added 'removeConfigurationListener' method.
953
954  Revision 1.55 2003/02/18 16:50:00 chr32
955  Added possibility to remove connection and state listeners.
956
957  Revision 1.54 2003/02/14 14:19:42 billhorsman
958  automatically load ProxoolDriver
959
960  Revision 1.53 2003/02/14 13:26:23 billhorsman
961  better exception for incorrect url
962
963  Revision 1.52 2003/02/12 12:28:27 billhorsman
964  added url, proxyHashcode and delegateHashcode to
965  ConnectionInfoIF
966
967  Revision 1.51 2003/02/07 17:26:05 billhorsman
968  deprecated removeAllConnectionPools in favour of
969  shutdown (and dropped unreliable finalize() method)
970
971  Revision 1.50 2003/02/07 15:12:41 billhorsman
972  fix statisticsLogLevel property recognition again
973
974  Revision 1.49 2003/02/07 14:45:40 billhorsman
975  fix statisticsLogLevel property recognition
976
977  Revision 1.48 2003/02/07 14:16:46 billhorsman
978  support for StatisticsListenerIF
979
980  Revision 1.47 2003/02/07 10:27:47 billhorsman
981  change in shutdown procedure to allow re-registration
982
983  Revision 1.46 2003/02/07 01:48:15 chr32
984  Started using new composite listeners.
985
986  Revision 1.45 2003/02/06 17:41:04 billhorsman
987  now uses imported logging
988
989  Revision 1.44 2003/02/06 15:46:43 billhorsman
990  checkstyle
991
992  Revision 1.43 2003/02/06 15:41:16 billhorsman
993  add statistics-log-level
994
995  Revision 1.42 2003/02/05 17:05:02 billhorsman
996  registerConnectionPool is now synchronized
997
998  Revision 1.41 2003/02/05 00:20:01 billhorsman
999  copes with pools with no statistics
1000
1001 Revision 1.40 2003/02/04 17:18:29 billhorsman
1002 move ShutdownHook init code
1003
1004 Revision 1.39 2003/02/04 15:04:17 billhorsman
1005 New ShutdownHook
1006
1007 Revision 1.38 2003/01/31 16:53:17 billhorsman
1008 checkstyle
1009
1010 Revision 1.37 2003/01/31 11:50:39 billhorsman
1011 changes for snapshot improvements
1012
1013 Revision 1.36 2003/01/31 00:18:27 billhorsman
1014 statistics is now a string to allow multiple,
1015 comma-delimited values (plus allow access to all
1016 statistics)
1017
1018 Revision 1.35 2003/01/30 17:50:28 billhorsman
1019 spelling
1020
1021 Revision 1.34 2003/01/30 17:48:50 billhorsman
1022 configuration listener now linked to alias not url
1023
1024 Revision 1.33 2003/01/30 17:22:23 billhorsman
1025 add statistics support
1026
1027 Revision 1.32 2003/01/27 18:26:36 billhorsman
1028 refactoring of ProxyConnection and ProxyStatement to
1029 make it easier to write JDK 1.2 patch
1030
1031 Revision 1.31 2003/01/23 11:08:26 billhorsman
1032 new setConfiguratorListener method (and remove from optional
1033 parameter when registering pool)
1034
1035 Revision 1.30 2003/01/19 15:21:07 billhorsman
1036 doc
1037
1038 Revision 1.29 2003/01/18 15:13:12 billhorsman
1039 Signature changes (new ProxoolException
1040 thrown) on the ProxoolFacade API.
1041
1042 Revision 1.28 2003/01/17 00:38:12 billhorsman
1043 wide ranging changes to clarify use of alias and url -
1044 this has led to some signature changes (new exceptions
1045 thrown) on the ProxoolFacade API.
1046
1047 Revision 1.27 2003/01/15 14:51:40 billhorsman
1048 checkstyle
1049
1050 Revision 1.26 2003/01/15 12:20:06 billhorsman
1051 deprecated getConnectionPoolStatisticsDump
1052
1053 Revision 1.25 2003/01/14 23:50:58 billhorsman
1054 logs version
1055
1056 Revision 1.24 2002/12/16 17:15:03 billhorsman
1057 fix for url
1058
1059 Revision 1.23 2002/12/16 16:47:22 billhorsman
1060 fix for updating properties with zero length strings
1061
1062 Revision 1.22 2002/12/16 16:42:30 billhorsman
1063 allow URL updates to pool
1064
1065 Revision 1.21 2002/12/16 11:46:00 billhorsman
1066 send properties to definitionUpdated
1067
1068 Revision 1.20 2002/12/16 11:16:51 billhorsman
1069 checkstyle
1070
1071 Revision 1.19 2002/12/16 11:15:19 billhorsman
1072 fixed getDelegateStatement
1073
1074 Revision 1.18 2002/12/16 10:57:48 billhorsman
1075 add getDelegateStatement to allow access to the
1076 delegate JDBC driver's Statement
1077
1078 Revision 1.17 2002/12/12 10:49:43 billhorsman
1079 now includes properties in definitionChanged event
1080
1081 Revision 1.16 2002/12/04 13:19:43 billhorsman
1082 draft ConfigurationListenerIF stuff for persistent configuration
1083
1084 Revision 1.15 2002/11/13 19:12:24 billhorsman
1085 fix where update properties weren't being recognised
1086 when the properties object was the same as the original
1087
1088 Revision 1.14 2002/11/13 11:28:38 billhorsman
1089 trace property wasn't being configured
1090
1091 Revision 1.13 2002/11/09 15:56:31 billhorsman
1092 log if serConnectionListener couldn't find pool
1093
1094 Revision 1.12 2002/11/03 10:46:57 billhorsman
1095 hide passwords in log
1096
1097 Revision 1.11 2002/11/02 13:57:33 billhorsman
1098 checkstyle
1099
1100 Revision 1.10 2002/10/29 08:54:45 billhorsman
1101 fix to getAlias so that it correctly extracts alias from "proxool.alias" form
1102
1103 Revision 1.9 2002/10/28 19:43:30 billhorsman
1104 configuring of pool now gets logged to that pool's logger (rather than general log)
1105
1106 Revision 1.8 2002/10/27 13:29:38 billhorsman
1107 deprecated debug-level in favour of verbose
1108
1109 Revision 1.7 2002/10/27 13:01:23 billhorsman
1110 layout
1111
1112 Revision 1.6 2002/10/25 15:59:32 billhorsman
1113 made non-public where possible
1114
1115 Revision 1.5 2002/10/25 10:12:52 billhorsman
1116 Improvements and fixes to the way connection pools close down. Including new ReloadMonitor to detect when a class is reloaded. Much better logging too.
1117
1118 Revision 1.4 2002/10/24 17:40:31 billhorsman
1119 Fixed recognition of existing pool (which was resulting in an extra configuration step - but which didn't cause any problems)
1120
1121 Revision 1.3 2002/10/23 21:04:36 billhorsman
1122 checkstyle fixes (reduced max line width and lenient naming convention
1123
1124 Revision 1.2 2002/10/17 15:27:31 billhorsman
1125 better reporting of property settings
1126
1127 Revision 1.1.1.1 2002/09/13 08:13:19 billhorsman
1128 new
1129
1130 Revision 1.11 2002/08/24 20:07:28 billhorsman
1131 removed debug to stdout
1132
1133 Revision 1.10 2002/08/24 19:44:13 billhorsman
1134 fixes for logging
1135
1136 Revision 1.9 2002/07/10 16:14:47 billhorsman
1137 widespread layout changes and move constants into ProxoolConstants
1138
1139 Revision 1.8 2002/07/05 13:24:32 billhorsman
1140 doc
1141
1142 Revision 1.7 2002/07/04 09:04:20 billhorsman
1143 Now throws an SQLException if you ask for a ConnectionPoolDefinition, ConnectionPoolStatistics that doesn't exist. This makes it easier to show the list of possible ones you can choose.
1144
1145 Revision 1.6 2002/07/02 11:19:08 billhorsman
1146 layout code and imports
1147
1148 Revision 1.5 2002/07/02 11:14:26 billhorsman
1149 added test (andbug fixes) for FileLogger
1150
1151 Revision 1.4 2002/07/02 09:13:08 billhorsman
1152 removed redundant import
1153
1154 Revision 1.3 2002/07/02 08:52:42 billhorsman
1155 Added lots more methods and moved configuration stuff here
1156
1157 Revision 1.2 2002/06/28 11:19:47 billhorsman
1158 improved doc
1159
1160*/

1161
Popular Tags