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.proxy.pojo.javassist;
26
27 import java.io.Serializable;
28 import java.lang.reflect.InvocationTargetException;
29 import java.lang.reflect.Method;
30
31 import javassist.util.proxy.MethodFilter;
32 import javassist.util.proxy.MethodHandler;
33 import javassist.util.proxy.ProxyFactory;
34 import javassist.util.proxy.ProxyObject;
35
36 import org.slf4j.LoggerFactory;
37 import org.hibernate.HibernateException;
38 import org.hibernate.engine.SessionImplementor;
39 import org.hibernate.proxy.pojo.BasicLazyInitializer;
40 import org.hibernate.proxy.HibernateProxy;
41 import org.hibernate.type.AbstractComponentType;
42 import org.hibernate.util.ReflectHelper;
43
44 /**
45 * A Javassist-based lazy initializer proxy.
46 *
47 * @author Muga Nishizawa
48 */
49 public class JavassistLazyInitializer extends BasicLazyInitializer implements MethodHandler {
50
51 private static final MethodFilter FINALIZE_FILTER = new MethodFilter() {
52 public boolean isHandled(Method m) {
53 // skip finalize methods
54 return !( m.getParameterTypes().length == 0 && m.getName().equals( "finalize" ) );
55 }
56 };
57
58 private Class[] interfaces;
59 private boolean constructed = false;
60
61 private JavassistLazyInitializer(
62 final String entityName,
63 final Class persistentClass,
64 final Class[] interfaces,
65 final Serializable id,
66 final Method getIdentifierMethod,
67 final Method setIdentifierMethod,
68 final AbstractComponentType componentIdType,
69 final SessionImplementor session) {
70 super( entityName, persistentClass, id, getIdentifierMethod, setIdentifierMethod, componentIdType, session );
71 this.interfaces = interfaces;
72 }
73
74 public static HibernateProxy getProxy(
75 final String entityName,
76 final Class persistentClass,
77 final Class[] interfaces,
78 final Method getIdentifierMethod,
79 final Method setIdentifierMethod,
80 AbstractComponentType componentIdType,
81 final Serializable id,
82 final SessionImplementor session) throws HibernateException {
83 // note: interface is assumed to already contain HibernateProxy.class
84 try {
85 final JavassistLazyInitializer instance = new JavassistLazyInitializer(
86 entityName,
87 persistentClass,
88 interfaces,
89 id,
90 getIdentifierMethod,
91 setIdentifierMethod,
92 componentIdType,
93 session
94 );
95 ProxyFactory factory = new ProxyFactory();
96 factory.setSuperclass( interfaces.length == 1 ? persistentClass : null );
97 factory.setInterfaces( interfaces );
98 factory.setFilter( FINALIZE_FILTER );
99 Class cl = factory.createClass();
100 final HibernateProxy proxy = ( HibernateProxy ) cl.newInstance();
101 ( ( ProxyObject ) proxy ).setHandler( instance );
102 instance.constructed = true;
103 return proxy;
104 }
105 catch ( Throwable t ) {
106 LoggerFactory.getLogger( BasicLazyInitializer.class ).error(
107 "Javassist Enhancement failed: " + entityName, t
108 );
109 throw new HibernateException(
110 "Javassist Enhancement failed: "
111 + entityName, t
112 );
113 }
114 }
115
116 public static HibernateProxy getProxy(
117 final Class factory,
118 final String entityName,
119 final Class persistentClass,
120 final Class[] interfaces,
121 final Method getIdentifierMethod,
122 final Method setIdentifierMethod,
123 final AbstractComponentType componentIdType,
124 final Serializable id,
125 final SessionImplementor session) throws HibernateException {
126
127 final JavassistLazyInitializer instance = new JavassistLazyInitializer(
128 entityName,
129 persistentClass,
130 interfaces, id,
131 getIdentifierMethod,
132 setIdentifierMethod,
133 componentIdType,
134 session
135 );
136
137 final HibernateProxy proxy;
138 try {
139 proxy = ( HibernateProxy ) factory.newInstance();
140 }
141 catch ( Exception e ) {
142 throw new HibernateException(
143 "Javassist Enhancement failed: "
144 + persistentClass.getName(), e
145 );
146 }
147 ( ( ProxyObject ) proxy ).setHandler( instance );
148 instance.constructed = true;
149 return proxy;
150 }
151
152 public static Class getProxyFactory(
153 Class persistentClass,
154 Class[] interfaces) throws HibernateException {
155 // note: interfaces is assumed to already contain HibernateProxy.class
156
157 try {
158 ProxyFactory factory = new ProxyFactory();
159 factory.setSuperclass( interfaces.length == 1 ? persistentClass : null );
160 factory.setInterfaces( interfaces );
161 factory.setFilter( FINALIZE_FILTER );
162 return factory.createClass();
163 }
164 catch ( Throwable t ) {
165 LoggerFactory.getLogger( BasicLazyInitializer.class ).error(
166 "Javassist Enhancement failed: "
167 + persistentClass.getName(), t
168 );
169 throw new HibernateException(
170 "Javassist Enhancement failed: "
171 + persistentClass.getName(), t
172 );
173 }
174 }
175
176 public Object invoke(
177 final Object proxy,
178 final Method thisMethod,
179 final Method proceed,
180 final Object[] args) throws Throwable {
181 if ( this.constructed ) {
182 Object result;
183 try {
184 result = this.invoke( thisMethod, args, proxy );
185 }
186 catch ( Throwable t ) {
187 throw new Exception( t.getCause() );
188 }
189 if ( result == INVOKE_IMPLEMENTATION ) {
190 Object target = getImplementation();
191 final Object returnValue;
192 try {
193 if ( ReflectHelper.isPublic( persistentClass, thisMethod ) ) {
194 if ( !thisMethod.getDeclaringClass().isInstance( target ) ) {
195 throw new ClassCastException( target.getClass().getName() );
196 }
197 returnValue = thisMethod.invoke( target, args );
198 }
199 else {
200 if ( !thisMethod.isAccessible() ) {
201 thisMethod.setAccessible( true );
202 }
203 returnValue = thisMethod.invoke( target, args );
204 }
205 return returnValue == target ? proxy : returnValue;
206 }
207 catch ( InvocationTargetException ite ) {
208 throw ite.getTargetException();
209 }
210 }
211 else {
212 return result;
213 }
214 }
215 else {
216 // while constructor is running
217 if ( thisMethod.getName().equals( "getHibernateLazyInitializer" ) ) {
218 return this;
219 }
220 else {
221 return proceed.invoke( proxy, args );
222 }
223 }
224 }
225
226 protected Object serializableProxy() {
227 return new SerializableProxy(
228 getEntityName(),
229 persistentClass,
230 interfaces,
231 getIdentifier(),
232 getIdentifierMethod,
233 setIdentifierMethod,
234 componentIdType
235 );
236 }
237 }