Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » proxy » pojo » cglib » [javadoc | source]
    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.cglib;
   26   
   27   import java.io.Serializable;
   28   import java.lang.reflect.InvocationTargetException;
   29   import java.lang.reflect.Method;
   30   
   31   import org.hibernate.repackage.cglib.proxy.Callback;
   32   import org.hibernate.repackage.cglib.proxy.CallbackFilter;
   33   import org.hibernate.repackage.cglib.proxy.Enhancer;
   34   import org.hibernate.repackage.cglib.proxy.InvocationHandler;
   35   import org.hibernate.repackage.cglib.proxy.NoOp;
   36   
   37   import org.hibernate.HibernateException;
   38   import org.hibernate.LazyInitializationException;
   39   import org.hibernate.proxy.pojo.BasicLazyInitializer;
   40   import org.hibernate.proxy.HibernateProxy;
   41   import org.hibernate.engine.SessionImplementor;
   42   import org.hibernate.type.AbstractComponentType;
   43   import org.hibernate.util.ReflectHelper;
   44   
   45   import org.slf4j.LoggerFactory;
   46   
   47   /**
   48    * A <tt>LazyInitializer</tt> implemented using the CGLIB bytecode generation library
   49    */
   50   public final class CGLIBLazyInitializer extends BasicLazyInitializer implements InvocationHandler {
   51   
   52   	private static final CallbackFilter FINALIZE_FILTER = new CallbackFilter() {
   53   		public int accept(Method method) {
   54   			if ( method.getParameterTypes().length == 0 && method.getName().equals("finalize") ){
   55   				return 1;
   56   			}
   57   			else {
   58   				return 0;
   59   			}
   60   		}
   61   	};
   62   
   63   	private Class[] interfaces;
   64   	private boolean constructed = false;
   65   
   66   	static HibernateProxy getProxy(final String entityName, final Class persistentClass,
   67   			final Class[] interfaces, final Method getIdentifierMethod,
   68   			final Method setIdentifierMethod, AbstractComponentType componentIdType,
   69   			final Serializable id, final SessionImplementor session) throws HibernateException {
   70   		// note: interfaces is assumed to already contain HibernateProxy.class
   71   
   72   		try {
   73   			final CGLIBLazyInitializer instance = new CGLIBLazyInitializer(
   74   					entityName,
   75   					persistentClass,
   76   					interfaces,
   77   					id,
   78   					getIdentifierMethod,
   79   					setIdentifierMethod,
   80   					componentIdType,
   81   					session
   82   				);
   83   
   84   			final HibernateProxy proxy;
   85   			Class factory = getProxyFactory(persistentClass,  interfaces);
   86   			proxy = getProxyInstance(factory, instance);
   87   			instance.constructed = true;
   88   			return proxy;
   89   		}
   90   		catch (Throwable t) {
   91   			LoggerFactory.getLogger( BasicLazyInitializer.class )
   92   				.error( "CGLIB Enhancement failed: " + entityName, t );
   93   			throw new HibernateException( "CGLIB Enhancement failed: " + entityName, t );
   94   		}
   95   	}
   96   
   97   	public static HibernateProxy getProxy(final Class factory, final String entityName,
   98   			final Class persistentClass, final Class[] interfaces,
   99   			final Method getIdentifierMethod, final Method setIdentifierMethod,
  100   			final AbstractComponentType componentIdType, final Serializable id,
  101   			final SessionImplementor session) throws HibernateException {
  102   
  103   		final CGLIBLazyInitializer instance = new CGLIBLazyInitializer(
  104   				entityName,
  105   				persistentClass,
  106   				interfaces,
  107   				id,
  108   				getIdentifierMethod,
  109   				setIdentifierMethod,
  110   				componentIdType,
  111   				session
  112   			);
  113   
  114   		final HibernateProxy proxy;
  115   		try {
  116   			proxy = getProxyInstance(factory, instance);
  117   		}
  118   		catch (Exception e) {
  119   			throw new HibernateException( "CGLIB Enhancement failed: " + persistentClass.getName(), e );
  120   		}
  121   		instance.constructed = true;
  122   
  123   		return proxy;
  124   	}
  125   
  126       private static HibernateProxy getProxyInstance(Class factory, CGLIBLazyInitializer instance) throws InstantiationException, IllegalAccessException {
  127   		HibernateProxy proxy;
  128   		try {
  129   			Enhancer.registerCallbacks(factory, new Callback[]{ instance, null });
  130   			proxy = (HibernateProxy)factory.newInstance();
  131   		} finally {
  132   			// HHH-2481 make sure the callback gets cleared, otherwise the instance stays in a static thread local.
  133   			Enhancer.registerCallbacks(factory, null);
  134   		}
  135   		return proxy;
  136   	}
  137   
  138   	public static Class getProxyFactory(Class persistentClass, Class[] interfaces)
  139   			throws HibernateException {
  140   		Enhancer e = new Enhancer();
  141   		e.setSuperclass( interfaces.length == 1 ? persistentClass : null );
  142   		e.setInterfaces(interfaces);
  143   		e.setCallbackTypes(new Class[]{
  144   			InvocationHandler.class,
  145   			NoOp.class,
  146   	  		});
  147     		e.setCallbackFilter(FINALIZE_FILTER);
  148     		e.setUseFactory(false);
  149   		e.setInterceptDuringConstruction( false );
  150   		return e.createClass();
  151   	}
  152   
  153   	private CGLIBLazyInitializer(final String entityName, final Class persistentClass,
  154   			final Class[] interfaces, final Serializable id, final Method getIdentifierMethod,
  155   			final Method setIdentifierMethod, final AbstractComponentType componentIdType,
  156   			final SessionImplementor session) {
  157   		super(
  158   				entityName,
  159   				persistentClass,
  160   				id,
  161   				getIdentifierMethod,
  162   				setIdentifierMethod,
  163   				componentIdType,
  164   				session
  165   			);
  166   		this.interfaces = interfaces;
  167   	}
  168   
  169   	public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
  170   		if ( constructed ) {
  171   			Object result = invoke( method, args, proxy );
  172   			if ( result == INVOKE_IMPLEMENTATION ) {
  173   				Object target = getImplementation();
  174   				try {
  175   					final Object returnValue;
  176   					if ( ReflectHelper.isPublic( persistentClass, method ) ) {
  177   						if ( !method.getDeclaringClass().isInstance( target ) ) {
  178   							throw new ClassCastException( target.getClass().getName() );
  179   						}
  180   						returnValue = method.invoke( target, args );
  181   					}
  182   					else {
  183   						if ( !method.isAccessible() ) {
  184   							method.setAccessible( true );
  185   						}
  186   						returnValue = method.invoke( target, args );
  187   					}
  188   					return returnValue == target ? proxy : returnValue;
  189   				}
  190   				catch ( InvocationTargetException ite ) {
  191   					throw ite.getTargetException();
  192   				}
  193   			}
  194   			else {
  195   				return result;
  196   			}
  197   		}
  198   		else {
  199   			// while constructor is running
  200   			if ( method.getName().equals( "getHibernateLazyInitializer" ) ) {
  201   				return this;
  202   			}
  203   			else {
  204   				throw new LazyInitializationException( "unexpected case hit, method=" + method.getName() );
  205   			}
  206   		}
  207   	}
  208   
  209   	protected Object serializableProxy() {
  210   		return new SerializableProxy(
  211   				getEntityName(),
  212   				persistentClass,
  213   				interfaces,
  214   				getIdentifier(),
  215   				getIdentifierMethod,
  216   				setIdentifierMethod,
  217   				componentIdType 
  218   			);
  219   	}
  220   
  221   }

Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » proxy » pojo » cglib » [javadoc | source]