KickJava   Java API By Example, From Geeks To Geeks.

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


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.logicalcobwebs.cglib.proxy.Enhancer;
9 import org.logicalcobwebs.cglib.proxy.Factory;
10 import org.logicalcobwebs.cglib.proxy.Callback;
11 import org.logicalcobwebs.cglib.core.NamingPolicy;
12 import org.logicalcobwebs.cglib.core.Predicate;
13 import org.apache.commons.logging.Log;
14 import org.apache.commons.logging.LogFactory;
15
16 import java.sql.Connection JavaDoc;
17 import java.sql.DatabaseMetaData JavaDoc;
18 import java.sql.Statement JavaDoc;
19 import java.sql.CallableStatement JavaDoc;
20 import java.sql.PreparedStatement JavaDoc;
21 import java.util.HashSet JavaDoc;
22 import java.util.Set JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.lang.reflect.Modifier JavaDoc;
26
27 /**
28  * A central place to build proxy objects. It will also provide the original
29  * object given a proxy.
30  * @author Bill Horsman (bill@logicalcobwebs.co.uk)
31  * @author $Author: billhorsman $ (current maintainer)
32  * @version $Revision: 1.33 $, $Date: 2006/04/09 21:08:43 $
33  * @since Proxool 0.5
34  */

35 class ProxyFactory {
36
37     private static final Log LOG = LogFactory.getLog(ProxyFactory.class);
38
39     private static Map JavaDoc interfaceMap = new HashMap JavaDoc();
40
41     /**
42      * This naming policy stops conflicts with other Cglib instances that are running
43      * (Even ones in different packages). Without using our own naming policy we end
44      * up with exceptions like:
45      * <pre>
46      * java.lang.LinkageError: duplicate class definition:
47      * $java/lang/Object$$FastClassByCGLIB$$3f697993
48      * </pre>
49      */

50     private static NamingPolicy NAMING_POLICY = new NamingPolicy() {
51         public String JavaDoc getClassName(String JavaDoc prefix, String JavaDoc source, Object JavaDoc key, Predicate names) {
52             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
53             sb.append(
54                     (prefix != null) ?
55                             (
56                                     prefix.startsWith("java") ?
57                                             "$" + prefix : prefix
58                             )
59                             : "net.sf.cglib.empty.Object"
60             );
61             sb.append("$$");
62             sb.append(source.substring(source.lastIndexOf('.') + 1));
63             sb.append("ByProxool$$");
64             sb.append(Integer.toHexString(key.hashCode()));
65             String JavaDoc base = sb.toString();
66             String JavaDoc attempt = base;
67             int index = 2;
68             while (names.evaluate(attempt)) {
69                 attempt = base + "_" + index++;
70             }
71
72             return attempt;
73         }
74     };
75
76     /**
77      * Wraps up a proxyConnection inside a {@link WrappedConnection} and then proxies it as a
78      * simple {@link Connection}. You should call this immediately before the connection is served
79      * to the user. The WrappedConnection is disposable (it is thrown away when the connection
80      * is returned to the pool).
81      * @param proxyConnection the pooled connection we are wrapping up
82      * @return the Connection for use
83      */

84     protected static Connection JavaDoc getWrappedConnection(ProxyConnection proxyConnection) {
85         return (Connection JavaDoc) getProxy(proxyConnection.getConnection(), new WrappedConnection(proxyConnection), proxyConnection.getDefinition());
86     }
87
88     /**
89      * Proxies a statement inside a {@link ProxyStatement}.
90      * @param delegate the real statement
91      * @param connectionPool the pool it belongs to
92      * @param proxyConnection the connection it was built from
93      * @param sqlStatement Can be null?
94      * @return the proxied statement
95      */

96     protected static Statement JavaDoc getStatement(Statement JavaDoc delegate, ConnectionPool connectionPool, ProxyConnectionIF proxyConnection, String JavaDoc sqlStatement) {
97         return (Statement JavaDoc) getProxy(delegate, new ProxyStatement(delegate, connectionPool, proxyConnection, sqlStatement), proxyConnection.getDefinition());
98     }
99
100     /**
101      * Create a new DatabaseMetaData from a connection
102      * @param databaseMetaData the meta data we use to delegate all calls to (except getConnection())
103      * @param wrappedConnection the connection we return if asked for the connection
104      * @return databaseMetaData
105      */

106     protected static DatabaseMetaData JavaDoc getDatabaseMetaData(DatabaseMetaData JavaDoc databaseMetaData, Connection JavaDoc wrappedConnection) {
107         return (DatabaseMetaData JavaDoc) getProxy(databaseMetaData, new ProxyDatabaseMetaData(databaseMetaData, wrappedConnection), null);
108     }
109
110     private static Object JavaDoc getProxy(Object JavaDoc delegate, Callback callback, ConnectionPoolDefinitionIF def) {
111         Enhancer e = new Enhancer();
112         e.setNamingPolicy(NAMING_POLICY);
113         e.setInterfaces(getInterfaces(delegate.getClass(), def));
114         e.setCallback(callback);
115         e.setClassLoader(ProxyFactory.class.getClassLoader());
116         return e.create();
117     }
118
119     /**
120      * Gets the real Statement that we got from the delegate driver. This is no longer
121      * necessary and only provided for backwards compatability.
122      * @param statement proxy statement
123      * @return delegate statement
124      * @see ProxoolFacade#getDelegateStatement(java.sql.Statement)
125      */

126     protected static Statement JavaDoc getDelegateStatement(Statement JavaDoc statement) {
127         Statement JavaDoc ds = statement;
128         ProxyStatement ps = (ProxyStatement) ((Factory)statement).getCallback(0);
129         ds = ps.getDelegateStatement();
130         return ds;
131     }
132
133     /**
134      * Gets the real Connection that we got from the delegate driver. This is no longer
135      * necessary and only provided for backwards compatability.
136      * @param connection proxy connection
137      * @return deletgate connection
138      * @see ProxoolFacade#getDelegateConnection(java.sql.Connection)
139      */

140     protected static Connection JavaDoc getDelegateConnection(Connection JavaDoc connection) {
141         WrappedConnection wc = (WrappedConnection) ((Factory)connection).getCallback(0);
142         return wc.getProxyConnection().getConnection();
143     }
144
145     /**
146      * Get all the interfaces that a class implements. Drills down into super interfaces too
147      * and super classes too.
148      * The results are cached so it's very fast second time round.
149      * @param clazz the class to examine.
150      * @return an array of classes (all interfaces) that this class implements.
151      */

152     private static Class JavaDoc[] getInterfaces(Class JavaDoc clazz, ConnectionPoolDefinitionIF cpd) {
153         Class JavaDoc[] interfaceArray = (Class JavaDoc[]) interfaceMap.get(clazz);
154         if (interfaceArray == null) {
155             Set JavaDoc interfaces = new HashSet JavaDoc();
156             traverseInterfacesRecursively(interfaces, clazz);
157             if (cpd != null) {
158                 // Work out which interface we should be injecting (if it has been configured). Make sure
159
// we check CallableStatement then PreparedStatement then Statement or all three will get
160
// caught by Statement
161
if (Connection JavaDoc.class.isAssignableFrom(clazz)) {
162                     Class JavaDoc injectableClass = cpd.getInjectableConnectionInterface();
163                     // Inject it if it was configured.
164
if (injectableClass != null) {
165                         interfaces.add(injectableClass);
166                         if (LOG.isDebugEnabled()) {
167                             LOG.debug("Injecting " + injectableClass + " into " + clazz);
168                         }
169                     }
170                 }
171                 if (CallableStatement JavaDoc.class.isAssignableFrom(clazz)) {
172                     if (LOG.isDebugEnabled()) {
173                         LOG.debug("Getting injectableCallableStatementInterface");
174                     }
175                     Class JavaDoc injectableClass = cpd.getInjectableCallableStatementInterface();
176                     // Inject it if it was configured.
177
if (injectableClass != null) {
178                         interfaces.add(injectableClass);
179                         if (LOG.isDebugEnabled()) {
180                             LOG.debug("Injecting " + injectableClass + " into " + clazz);
181                         }
182                     }
183                 }
184                 if (PreparedStatement JavaDoc.class.isAssignableFrom(clazz)) {
185                     Class JavaDoc injectableClass = cpd.getInjectablePreparedStatementInterface();
186                     // Inject it if it was configured.
187
if (injectableClass != null) {
188                         interfaces.add(injectableClass);
189                         if (LOG.isDebugEnabled()) {
190                             LOG.debug("Injecting " + injectableClass + " into " + clazz);
191                         }
192                     }
193                 }
194                 if (Statement JavaDoc.class.isAssignableFrom(clazz)) {
195                     Class JavaDoc injectableClass = cpd.getInjectableStatementInterface();
196                     // Inject it if it was configured.
197
if (injectableClass != null) {
198                         interfaces.add(injectableClass);
199                         if (LOG.isDebugEnabled()) {
200                             LOG.debug("Injecting " + injectableClass + " into " + clazz);
201                         }
202                     }
203                 }
204             }
205             interfaceArray = (Class JavaDoc[]) interfaces.toArray(new Class JavaDoc[interfaces.size()]);
206             if (LOG.isDebugEnabled()) {
207                 for (int i = 0; i < interfaceArray.length; i++) {
208                     Class JavaDoc aClass = interfaceArray[i];
209                     LOG.debug("Implementing " + aClass);
210                 }
211             }
212             interfaceMap.put(clazz, interfaceArray);
213 /*
214         } else {
215             if (LOG.isDebugEnabled()) {
216                 LOG.debug("Reusing " + interfaceArray.length + " interfaces already looked up for " + clazz);
217             }
218 */

219         }
220         return interfaceArray;
221     }
222
223     /**
224      * Recursively looks at all interfaces for a class. Also looks at interfaces implemented
225      * by the super class (and its super class, etc.) Quite a lot of processing involved
226      * so you shouldn't call it too often.
227      * @param interfaces this set is populated with all interfaceMap it finds
228      * @param clazz the base class to analyze
229      */

230     private static void traverseInterfacesRecursively(Set JavaDoc interfaces, Class JavaDoc clazz) {
231         // Check for circular reference (avoid endless recursion)
232
if (interfaces.contains(clazz)) {
233             // Skip it, we've already been here.
234
/*
235             if (LOG.isDebugEnabled()) {
236                 LOG.debug("Skipping " + clazz + " because we've already traversed it");
237             }
238 */

239         } else {
240 /*
241             if (LOG.isDebugEnabled()) {
242                 LOG.debug("Analyzing " + clazz);
243             }
244 */

245             Class JavaDoc[] interfaceArray = clazz.getInterfaces();
246             for (int i = 0; i < interfaceArray.length; i++) {
247 /*
248                 if (LOG.isDebugEnabled()) {
249                     LOG.debug("Adding " + interfaceArray[i]);
250                 }
251 */

252                 traverseInterfacesRecursively(interfaces, interfaceArray[i]);
253                 // We're only interested in public interfaces. In fact, including
254
// non-public interfaces will give IllegalAccessExceptions.
255
if (Modifier.isPublic(interfaceArray[i].getModifiers())) {
256                     interfaces.add(interfaceArray[i]);
257                 }
258             }
259             Class JavaDoc superClazz = clazz.getSuperclass();
260             if (superClazz != null) {
261                 traverseInterfacesRecursively(interfaces, superClazz);
262             }
263 /*
264             if (LOG.isDebugEnabled()) {
265                 LOG.debug("Found " + interfaceArray.length + " interfaceMap for " + clazz);
266             }
267 */

268         }
269     }
270
271     /**
272      * Get the WrappedConnection behind this proxy connection.
273      * @param connection the connection that was served
274      * @return the wrapped connection or null if it couldn't be found
275      */

276     public static WrappedConnection getWrappedConnection(Connection JavaDoc connection) {
277         return (WrappedConnection) ((Factory)connection).getCallback(0);
278     }
279
280 }
281
282 /*
283  Revision history:
284  $Log: ProxyFactory.java,v $
285  Revision 1.33 2006/04/09 21:08:43 billhorsman
286  Use our own naming policy for Cglib to avoid duplicate class definition exceptions.
287
288  Revision 1.32 2006/01/18 14:40:02 billhorsman
289  Unbundled Jakarta's Commons Logging.
290
291  Revision 1.31 2005/09/26 09:59:22 billhorsman
292  Explicitly use the ProxyFactory class loader when using Cglib's Enhancer to avoid class loading issues.
293
294  Revision 1.30 2005/05/04 16:31:41 billhorsman
295  Use the definition referenced by the proxy connection rather than the pool instead.
296
297  Revision 1.29 2004/07/27 21:44:15 billhorsman
298  Remove insane amount of debug logging.
299
300  Revision 1.28 2004/06/17 21:58:36 billhorsman
301  Injectable interface fixes.
302
303  Revision 1.27 2004/06/02 20:50:47 billhorsman
304  Dropped obsolete InvocationHandler reference and injectable interface stuff.
305
306  Revision 1.26 2004/03/23 21:19:45 billhorsman
307  Added disposable wrapper to proxied connection. And made proxied objects implement delegate interfaces too.
308
309  Revision 1.25 2003/12/12 19:29:47 billhorsman
310  Now uses Cglib 2.0
311
312  Revision 1.24 2003/09/30 18:39:08 billhorsman
313  New test-before-use, test-after-use and fatal-sql-exception-wrapper-class properties.
314
315  Revision 1.23 2003/09/10 22:21:04 chr32
316  Removing > jdk 1.2 dependencies.
317
318  Revision 1.22 2003/09/07 22:11:31 billhorsman
319  Remove very persistent debug message
320
321  Revision 1.21 2003/08/27 18:03:20 billhorsman
322  added new getDelegateConnection() method
323
324  Revision 1.20 2003/03/11 14:51:54 billhorsman
325  more concurrency fixes relating to snapshots
326
327  Revision 1.19 2003/03/10 23:43:13 billhorsman
328  reapplied checkstyle that i'd inadvertently let
329  IntelliJ change...
330
331  Revision 1.18 2003/03/10 15:26:49 billhorsman
332  refactoringn of concurrency stuff (and some import
333  optimisation)
334
335  Revision 1.17 2003/03/05 18:42:33 billhorsman
336  big refactor of prototyping and house keeping to
337  drastically reduce the number of threads when using
338  many pools
339
340  Revision 1.16 2003/03/03 11:11:58 billhorsman
341  fixed licence
342
343  Revision 1.15 2003/02/19 15:14:32 billhorsman
344  fixed copyright (copy and paste error,
345  not copyright change)
346
347  Revision 1.14 2003/02/12 12:28:27 billhorsman
348  added url, proxyHashcode and delegateHashcode to
349  ConnectionInfoIF
350
351  Revision 1.13 2003/02/06 17:41:04 billhorsman
352  now uses imported logging
353
354  Revision 1.12 2003/01/31 14:33:18 billhorsman
355  fix for DatabaseMetaData
356
357  Revision 1.11 2003/01/27 18:26:39 billhorsman
358  refactoring of ProxyConnection and ProxyStatement to
359  make it easier to write JDK 1.2 patch
360
361  Revision 1.10 2002/12/16 11:15:19 billhorsman
362  fixed getDelegateStatement
363
364  Revision 1.9 2002/12/16 10:57:47 billhorsman
365  add getDelegateStatement to allow access to the
366  delegate JDBC driver's Statement
367
368  Revision 1.8 2002/12/12 10:48:25 billhorsman
369  checkstyle
370
371  Revision 1.7 2002/12/08 22:17:35 billhorsman
372  debug for proxying statement interfaces
373
374  Revision 1.6 2002/12/06 15:57:08 billhorsman
375  fix for proxied statement where Statement interface is not directly
376  implemented.
377
378  Revision 1.5 2002/12/03 12:24:00 billhorsman
379  fixed fatal sql exception
380
381  Revision 1.4 2002/11/09 15:56:52 billhorsman
382  fix doc
383
384  Revision 1.3 2002/11/02 14:22:15 billhorsman
385  Documentation
386
387  Revision 1.2 2002/10/30 21:25:08 billhorsman
388  move createStatement into ProxyFactory
389
390  Revision 1.1 2002/10/30 21:19:16 billhorsman
391  make use of ProxyFactory
392
393 */

394
Popular Tags