Package org.hibernate.ejb.util

Source Code of org.hibernate.ejb.util.PersistenceUtilHelper$MetadataCache$ClassCache

package org.hibernate.ejb.util;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.AccessibleObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import javax.persistence.spi.LoadState;
import javax.persistence.PersistenceException;

import org.hibernate.AssertionFailure;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.intercept.FieldInterceptionHelper;
import org.hibernate.intercept.FieldInterceptor;
import org.hibernate.collection.PersistentCollection;

/**
* @author Emmanuel Bernard
* @author Hardy Ferentschik
*/
public class PersistenceUtilHelper {
  public static LoadState isLoadedWithoutReference(Object proxy, String property, MetadataCache cache) {
    Object entity;
    boolean sureFromUs = false;
    if ( proxy instanceof HibernateProxy ) {
      LazyInitializer li = ( ( HibernateProxy ) proxy ).getHibernateLazyInitializer();
      if ( li.isUninitialized() ) {
        return LoadState.NOT_LOADED;
      }
      else {
        entity = li.getImplementation();
      }
      sureFromUs = true;
    }
    else {
      entity = proxy;
    }

    //we are instrumenting but we can't assume we are the only ones
    if ( FieldInterceptionHelper.isInstrumented( entity ) ) {
      FieldInterceptor interceptor = FieldInterceptionHelper.extractFieldInterceptor( entity );
      final boolean isInitialized = interceptor == null || interceptor.isInitialized( property );
      LoadState state;
      if (isInitialized && interceptor != null) {
        //property is loaded according to bytecode enhancement, but is it loaded as far as association?
        //it's ours, we can read
        state = isLoaded( get( entity, property, cache ) );
        //it's ours so we know it's loaded
        if (state == LoadState.UNKNOWN) state = LoadState.LOADED;
      }
      else if ( interceptor != null && (! isInitialized)) {
        state = LoadState.NOT_LOADED;
      }
      else if ( sureFromUs ) { //interceptor == null
        //property is loaded according to bytecode enhancement, but is it loaded as far as association?
        //it's ours, we can read
        state = isLoaded( get( entity, property, cache ) );
        //it's ours so we know it's loaded
        if (state == LoadState.UNKNOWN) state = LoadState.LOADED;
      }
      else {
        state = LoadState.UNKNOWN;
      }

      return state;
    }
    else {
      //can't do sureFromUs ? LoadState.LOADED : LoadState.UNKNOWN;
      //is that an association?
      return LoadState.UNKNOWN;
    }
  }

  public static LoadState isLoadedWithReference(Object proxy, String property, MetadataCache cache) {
    //for sure we don't instrument and for sure it's not a lazy proxy
    Object object = get(proxy, property, cache);
    return isLoaded( object );
  }

  private static Object get(Object proxy, String property, MetadataCache cache) {
    final Class<?> clazz = proxy.getClass();

    try {
      Member member = cache.getMember( clazz, property );
      if (member instanceof Field) {
        return ( (Field) member ).get( proxy );
      }
      else if (member instanceof Method) {
        return ( (Method) member ).invoke( proxy );
      }
      else {
        throw new AssertionFailure( "Member object neither Field nor Method: " + member);
      }
    }
    catch ( IllegalAccessException e ) {
      throw new PersistenceException( "Unable to access field or method: "
              + clazz + "#"
              + property, e);
    }
    catch ( InvocationTargetException e ) {
      throw new PersistenceException( "Unable to access field or method: "
              + clazz + "#"
              + property, e);
    }
  }

  private static void setAccessibility(Member member) {
    //Sun's ease of use, sigh...
    ( ( AccessibleObject ) member ).setAccessible( true );
  }

  public static LoadState isLoaded(Object o) {
    if ( o instanceof HibernateProxy ) {
      final boolean isInitialized = !( ( HibernateProxy ) o ).getHibernateLazyInitializer().isUninitialized();
      return isInitialized ? LoadState.LOADED : LoadState.NOT_LOADED;
    }
    else if ( o instanceof PersistentCollection ) {
      final boolean isInitialized = ( ( PersistentCollection ) o ).wasInitialized();
      return isInitialized ? LoadState.LOADED : LoadState.NOT_LOADED;
    }
    else {
      return LoadState.UNKNOWN;
    }
  }

  /**
   * Returns the method with the specified name or <code>null</code> if it does not exist.
   *
   * @param clazz The class to check.
   * @param methodName The method name.
   *
   * @return Returns the method with the specified name or <code>null</code> if it does not exist.
   */
  private static Method getMethod(Class<?> clazz, String methodName) {
    try {
      char string[] = methodName.toCharArray();
      string[0] = Character.toUpperCase( string[0] );
      methodName = new String( string );
      try {
        return clazz.getDeclaredMethod( "get" + methodName );
      }
      catch ( NoSuchMethodException e ) {
        return clazz.getDeclaredMethod( "is" + methodName );
      }
    }
    catch ( NoSuchMethodException e ) {
      return null;
    }
  }

  /**
   * Cache hierarchy and member resolution in a weak hash map
   */
  //TODO not really thread-safe
  public static class MetadataCache implements Serializable {
    private transient Map<Class<?>, ClassCache> classCache = new WeakHashMap<Class<?>, ClassCache>();


    private void readObject(java.io.ObjectInputStream stream) {
      classCache = new WeakHashMap<Class<?>, ClassCache>();
    }

    Member getMember(Class<?> clazz, String property) {
      ClassCache cache = classCache.get( clazz );
      if (cache == null) {
        cache = new ClassCache(clazz);
        classCache.put( clazz, cache );
      }
      Member member = cache.members.get( property );
      if ( member == null ) {
        member = findMember( clazz, property );
        cache.members.put( property, member );
      }
      return member;
    }

    private Member findMember(Class<?> clazz, String property) {
      final List<Class<?>> classes = getClassHierarchy( clazz );

      for (Class current : classes) {
        final Field field;
        try {
          field = current.getDeclaredField( property );
          setAccessibility( field );
          return field;
        }
        catch ( NoSuchFieldException e ) {
          final Method method = getMethod( current, property );
          if (method != null) {
            setAccessibility( method );
            return method;
          }
        }
      }
      //we could not find any match
      throw new PersistenceException( "Unable to find field or method: "
              + clazz + "#"
              + property);
    }

    private List<Class<?>> getClassHierarchy(Class<?> clazz) {
      ClassCache cache = classCache.get( clazz );
      if (cache == null) {
        cache = new ClassCache(clazz);
        classCache.put( clazz, cache );
      }
      return cache.classHierarchy;
    }

    private static List<Class<?>> findClassHierarchy(Class<?> clazz) {
      List<Class<?>> classes = new ArrayList<Class<?>>();
      Class<?> current = clazz;
      do {
        classes.add( current );
        current = current.getSuperclass();
      }
      while ( current != null );
      return classes;
    }

    private static class ClassCache {
      List<Class<?>> classHierarchy;
      Map<String, Member> members = new HashMap<String, Member>();

      public ClassCache(Class<?> clazz) {
        classHierarchy = findClassHierarchy( clazz );
      }
    }
  }

}
TOP

Related Classes of org.hibernate.ejb.util.PersistenceUtilHelper$MetadataCache$ClassCache

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.