Open Source Repository

Home /hibernate/hibernate-3.2.7.ga | Repository Home


org/hibernate/proxy/pojo/cglib/CGLIBLazyInitializer.java
// $Id: CGLIBLazyInitializer.java 11296 2007-03-18 04:10:09Z scottmarlownovell $
package org.hibernate.proxy.pojo.cglib;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.InvocationHandler;
import net.sf.cglib.proxy.NoOp;

import org.hibernate.HibernateException;
import org.hibernate.LazyInitializationException;
import org.hibernate.proxy.pojo.BasicLazyInitializer;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.type.AbstractComponentType;
import org.hibernate.util.ReflectHelper;

import org.apache.commons.logging.LogFactory;

/**
 * A <tt>LazyInitializer</tt> implemented using the CGLIB bytecode generation library
 */
public final class CGLIBLazyInitializer extends BasicLazyInitializer implements InvocationHandler {
  
  private static final CallbackFilter FINALIZE_FILTER = new CallbackFilter() {
    public int accept(Method method) {
      if method.getParameterTypes().length == && method.getName().equals("finalize") ){
        return 1;
      }
      else {
        return 0;
      }
    }
  };

  private Class[] interfaces;
  private boolean constructed = false;

  static HibernateProxy getProxy(final String entityName, final Class persistentClass,
      final Class[] interfaces, final Method getIdentifierMethod,
      final Method setIdentifierMethod, AbstractComponentType componentIdType,
      final Serializable id, final SessionImplementor sessionthrows HibernateException {
    // note: interfaces is assumed to already contain HibernateProxy.class
    
    try {
      final CGLIBLazyInitializer instance = new CGLIBLazyInitializer(
          entityName,
          persistentClass,
          interfaces,
          id,
          getIdentifierMethod,
          setIdentifierMethod,
          componentIdType,
          session 
        );
      
      final HibernateProxy proxy;
      Class factory = getProxyFactory(persistentClass,  interfaces);
      proxy = getProxyInstance(factory, instance);
      instance.constructed = true;
      return proxy;
    }
    catch (Throwable t) {
      LogFactory.getLogBasicLazyInitializer.class )
        .error"CGLIB Enhancement failed: " + entityName, t );
      throw new HibernateException"CGLIB Enhancement failed: " + entityName, t );
    }
  }

  public static HibernateProxy getProxy(final Class factory, final String entityName,
      final Class persistentClass, final Class[] interfaces,
      final Method getIdentifierMethod, final Method setIdentifierMethod,
      final AbstractComponentType componentIdType, final Serializable id,
      final SessionImplementor sessionthrows HibernateException {
    
    final CGLIBLazyInitializer instance = new CGLIBLazyInitializer(
        entityName,
        persistentClass,
        interfaces,
        id,
        getIdentifierMethod,
        setIdentifierMethod,
        componentIdType,
        session 
      );
    
    final HibernateProxy proxy;
    try {
      proxy = getProxyInstance(factory, instance);
    }
    catch (Exception e) {
      throw new HibernateException"CGLIB Enhancement failed: " + persistentClass.getName(), e );
    }
    instance.constructed = true;

    return proxy;
  }

    private static HibernateProxy getProxyInstance(Class factory, CGLIBLazyInitializer instancethrows InstantiationException, IllegalAccessException {
    HibernateProxy proxy;
    try {
      Enhancer.registerCallbacks(factory, new Callback[]{ instance, null });
      proxy = (HibernateProxy)factory.newInstance();
    finally {
      // HHH-2481 make sure the callback gets cleared, otherwise the instance stays in a static thread local.
      Enhancer.registerCallbacks(factory, null);
    }
    return proxy;
  }

    public static Class getProxyFactory(Class persistentClass, Class[] interfaces)
      throws HibernateException {
    Enhancer e = new Enhancer();
    e.setSuperclassinterfaces.length == ? persistentClass : null );
    e.setInterfaces(interfaces);
    e.setCallbackTypes(new Class[]{
      InvocationHandler.class,
      NoOp.class,
        });
      e.setCallbackFilter(FINALIZE_FILTER);
      e.setUseFactory(false);
    e.setInterceptDuringConstructionfalse );
    return e.createClass();
  }

  private CGLIBLazyInitializer(final String entityName, final Class persistentClass,
      final Class[] interfaces, final Serializable id, final Method getIdentifierMethod,
      final Method setIdentifierMethod, final AbstractComponentType componentIdType,
      final SessionImplementor session) {
    super(
        entityName,
        persistentClass,
        id,
        getIdentifierMethod,
        setIdentifierMethod,
        componentIdType,
        session 
      );
    this.interfaces = interfaces;
  }

  public Object invoke(final Object proxy, final Method method, final Object[] argsthrows Throwable {
    if constructed ) {
      Object result = invokemethod, args, proxy );
      if result == INVOKE_IMPLEMENTATION ) {
        Object target = getImplementation();
        try {
          final Object returnValue;
          if ReflectHelper.isPublicpersistentClass, method ) ) {
            if ! method.getDeclaringClass().isInstancetarget ) ) {
              throw new ClassCastExceptiontarget.getClass().getName() );
            }
            returnValue = method.invoketarget, args );
          }
          else {
            if !method.isAccessible() ) {
              method.setAccessibletrue );
            }
            returnValue = method.invoketarget, args );
          }
          return returnValue == target ? proxy : returnValue;
        }
        catch InvocationTargetException ite ) {
          throw ite.getTargetException();
        }
      }
      else {
        return result;
      }
    }
    else {
      // while constructor is running
      if method.getName().equals"getHibernateLazyInitializer" ) ) {
        return this;
      }
      else {
        throw new LazyInitializationException"unexpected case hit, method=" + method.getName() );
      }
    }
  }

  protected Object serializableProxy() {
    return new SerializableProxy(
        getEntityName(),
        persistentClass,
        interfaces,
        getIdentifier(),
        getIdentifierMethod,
        setIdentifierMethod,
        componentIdType 
      );
  }

}