1 /*
2 * Hibernate, Relational Persistence for Idiomatic Java
3 *
4 * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
5 * indicated by the @author tags or express copyright attribution
6 * statements applied by the authors. All third-party contributions are
7 * distributed under license by Red Hat Middleware LLC.
8 *
9 * This copyrighted material is made available to anyone wishing to use, modify,
10 * copy, or redistribute it subject to the terms and conditions of the GNU
11 * Lesser General Public License, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this distribution; if not, write to:
20 * Free Software Foundation, Inc.
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301 USA
23 *
24 */
25 package org.hibernate.jdbc;
26
27 import org.hibernate.HibernateException;
28
29 import java.lang.reflect.InvocationHandler;
30 import java.lang.reflect.Method;
31 import java.lang.reflect.Proxy;
32 import java.lang.reflect.InvocationTargetException;
33 import java.sql.Connection;
34
35 /**
36 * A proxy for <i>borrowed</i> connections which funnels all requests back
37 * into the ConnectionManager from which it was borrowed to be properly
38 * handled (in terms of connection release modes).
39 * <p/>
40 * Note: the term borrowed here refers to connection references obtained
41 * via {@link org.hibernate.Session#connection()} for application usage.
42 *
43 * @author Steve Ebersole
44 */
45 public class BorrowedConnectionProxy implements InvocationHandler {
46
47 private static final Class[] PROXY_INTERFACES = new Class[] { Connection.class, ConnectionWrapper.class };
48
49 private final ConnectionManager connectionManager;
50 private boolean useable = true;
51
52 public BorrowedConnectionProxy(ConnectionManager connectionManager) {
53 this.connectionManager = connectionManager;
54 }
55
56 /**
57 * {@inheritDoc}
58 */
59 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
60 if ( "close".equals( method.getName() ) ) {
61 connectionManager.releaseBorrowedConnection();
62 return null;
63 }
64 // should probably no-op commit/rollback here, at least in JTA scenarios
65 if ( !useable ) {
66 throw new HibernateException( "connnection proxy not usable after transaction completion" );
67 }
68
69 if ( "getWrappedConnection".equals( method.getName() ) ) {
70 return connectionManager.getConnection();
71 }
72
73 try {
74 return method.invoke( connectionManager.getConnection(), args );
75 }
76 catch( InvocationTargetException e ) {
77 throw e.getTargetException();
78 }
79 }
80
81 /**
82 * Generates a Connection proxy wrapping the connection managed by the passed
83 * connection manager.
84 *
85 * @param connectionManager The connection manager to wrap with the
86 * connection proxy.
87 * @return The generated proxy.
88 */
89 public static Connection generateProxy(ConnectionManager connectionManager) {
90 BorrowedConnectionProxy handler = new BorrowedConnectionProxy( connectionManager );
91 return ( Connection ) Proxy.newProxyInstance(
92 getProxyClassLoader(),
93 PROXY_INTERFACES,
94 handler
95 );
96 }
97
98 /**
99 * Marks a borrowed connection as no longer usable.
100 *
101 * @param connection The connection (proxy) to be marked.
102 */
103 public static void renderUnuseable(Connection connection) {
104 if ( connection != null && Proxy.isProxyClass( connection.getClass() ) ) {
105 InvocationHandler handler = Proxy.getInvocationHandler( connection );
106 if ( BorrowedConnectionProxy.class.isAssignableFrom( handler.getClass() ) ) {
107 ( ( BorrowedConnectionProxy ) handler ).useable = false;
108 }
109 }
110 }
111
112 /**
113 * Convience method for unwrapping a connection proxy and getting a
114 * handle to an underlying connection.
115 *
116 * @param connection The connection (proxy) to be unwrapped.
117 * @return The unwrapped connection.
118 */
119 public static Connection getWrappedConnection(Connection connection) {
120 if ( connection != null && connection instanceof ConnectionWrapper ) {
121 return ( ( ConnectionWrapper ) connection ).getWrappedConnection();
122 }
123 else {
124 return connection;
125 }
126 }
127
128 /**
129 * Determines the appropriate class loader to which the generated proxy
130 * should be scoped.
131 *
132 * @return The class loader appropriate for proxy construction.
133 */
134 public static ClassLoader getProxyClassLoader() {
135 ClassLoader cl = Thread.currentThread().getContextClassLoader();
136 if ( cl == null ) {
137 cl = BorrowedConnectionProxy.class.getClassLoader();
138 }
139 return cl;
140 }
141 }