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.bytecode.cglib; 26 27 import org.hibernate.bytecode.ProxyFactoryFactory; 28 import org.hibernate.bytecode.BasicProxyFactory; 29 import org.hibernate.proxy.ProxyFactory; 30 import org.hibernate.proxy.pojo.cglib.CGLIBProxyFactory; 31 import org.hibernate.AssertionFailure; 32 import org.hibernate.HibernateException; 33 import net.sf.cglib.proxy.Enhancer; 34 import net.sf.cglib.proxy.CallbackFilter; 35 import net.sf.cglib.proxy.MethodInterceptor; 36 import net.sf.cglib.proxy.MethodProxy; 37 import net.sf.cglib.proxy.NoOp; 38 import net.sf.cglib.proxy.Callback; 39 import net.sf.cglib.proxy.Factory; 40 41 import java.lang.reflect.Method; 42 import java.util.HashMap; 43 44 /** 45 * A factory for CGLIB-based {@link ProxyFactory} instances. 46 * 47 * @author Steve Ebersole 48 */ 49 public class ProxyFactoryFactoryImpl implements ProxyFactoryFactory { 50 51 /** 52 * Builds a CGLIB-based proxy factory. 53 * 54 * @return a new CGLIB-based proxy factory. 55 */ 56 public ProxyFactory buildProxyFactory() { 57 return new CGLIBProxyFactory(); 58 } 59 60 public BasicProxyFactory buildBasicProxyFactory(Class superClass, Class[] interfaces) { 61 return new BasicProxyFactoryImpl( superClass, interfaces ); 62 } 63 64 public static class BasicProxyFactoryImpl implements BasicProxyFactory { 65 private final Class proxyClass; 66 private final Factory factory; 67 68 public BasicProxyFactoryImpl(Class superClass, Class[] interfaces) { 69 if ( superClass == null && ( interfaces == null || interfaces.length < 1 ) ) { 70 throw new AssertionFailure( "attempting to build proxy without any superclass or interfaces" ); 71 } 72 73 Enhancer en = new Enhancer(); 74 en.setUseCache( false ); 75 en.setInterceptDuringConstruction( false ); 76 en.setUseFactory( true ); 77 en.setCallbackTypes( CALLBACK_TYPES ); 78 en.setCallbackFilter( FINALIZE_FILTER ); 79 if ( superClass != null ) { 80 en.setSuperclass( superClass ); 81 } 82 if ( interfaces != null && interfaces.length > 0 ) { 83 en.setInterfaces( interfaces ); 84 } 85 proxyClass = en.createClass(); 86 try { 87 factory = ( Factory ) proxyClass.newInstance(); 88 } 89 catch ( Throwable t ) { 90 throw new HibernateException( "Unable to build CGLIB Factory instance" ); 91 } 92 } 93 94 public Object getProxy() { 95 try { 96 return factory.newInstance( 97 new Callback[] { new PassThroughInterceptor( proxyClass.getName() ), NoOp.INSTANCE } 98 ); 99 } 100 catch ( Throwable t ) { 101 throw new HibernateException( "Unable to instantiate proxy instance" ); 102 } 103 } 104 } 105 106 private static final CallbackFilter FINALIZE_FILTER = new CallbackFilter() { 107 public int accept(Method method) { 108 if ( method.getParameterTypes().length == 0 && method.getName().equals("finalize") ){ 109 return 1; 110 } 111 else { 112 return 0; 113 } 114 } 115 }; 116 117 private static final Class[] CALLBACK_TYPES = new Class[] { MethodInterceptor.class, NoOp.class }; 118 119 private static class PassThroughInterceptor implements MethodInterceptor { 120 private HashMap data = new HashMap(); 121 private final String proxiedClassName; 122 123 public PassThroughInterceptor(String proxiedClassName) { 124 this.proxiedClassName = proxiedClassName; 125 } 126 127 public Object intercept( 128 Object obj, 129 Method method, 130 Object[] args, 131 MethodProxy proxy) throws Throwable { 132 String name = method.getName(); 133 if ( "toString".equals( name ) ) { 134 return proxiedClassName + "@" + System.identityHashCode( obj ); 135 } 136 else if ( "equals".equals( name ) ) { 137 return args[0] instanceof Factory && ( ( Factory ) args[0] ).getCallback( 0 ) == this 138 ? Boolean.TRUE 139 : Boolean.FALSE; 140 } 141 else if ( "hashCode".equals( name ) ) { 142 return new Integer( System.identityHashCode( obj ) ); 143 } 144 boolean hasGetterSignature = method.getParameterTypes().length == 0 && method.getReturnType() != null; 145 boolean hasSetterSignature = method.getParameterTypes().length == 1 && ( method.getReturnType() == null || method.getReturnType() == void.class ); 146 if ( name.startsWith( "get" ) && hasGetterSignature ) { 147 String propName = name.substring( 3 ); 148 return data.get( propName ); 149 } 150 else if ( name.startsWith( "is" ) && hasGetterSignature ) { 151 String propName = name.substring( 2 ); 152 return data.get( propName ); 153 } 154 else if ( name.startsWith( "set" ) && hasSetterSignature) { 155 String propName = name.substring( 3 ); 156 data.put( propName, args[0] ); 157 return null; 158 } 159 else { 160 // todo : what else to do here? 161 return null; 162 } 163 } 164 } 165 }