Package org.hibernate.ejb.event

Source Code of org.hibernate.ejb.event.CallbackResolver

/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2009-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.  All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA  02110-1301  USA
*/
package org.hibernate.ejb.event;

import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.ExcludeDefaultListeners;
import javax.persistence.ExcludeSuperclassListeners;
import javax.persistence.MappedSuperclass;
import javax.persistence.PersistenceException;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.jboss.logging.Logger;

import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XMethod;
import org.hibernate.ejb.internal.EntityManagerMessageLogger;
import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.source.binder.JpaCallbackClass;
import org.hibernate.service.classloading.spi.ClassLoaderService;

/**
* @author <a href="mailto:kabir.khan@jboss.org">Kabir Khan</a>
*/
public final class CallbackResolver {

    private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
                                                                           CallbackResolver.class.getName());

  private static boolean useAnnotationAnnotatedByListener;

  static {
    //check whether reading annotations of annotations is useful or not
    useAnnotationAnnotatedByListener = false;
    Target target = EntityListeners.class.getAnnotation( Target.class );
    if ( target != null ) {
      for ( ElementType type : target.value() ) {
        if ( type.equals( ElementType.ANNOTATION_TYPE ) ) useAnnotationAnnotatedByListener = true;
      }
    }
  }

  private CallbackResolver() {
  }

  public static Callback[] resolveCallback(XClass beanClass, Class annotation, ReflectionManager reflectionManager) {
    List<Callback> callbacks = new ArrayList<Callback>();
    List<String> callbacksMethodNames = new ArrayList<String>(); //used to track overridden methods
    List<Class> orderedListeners = new ArrayList<Class>();
    XClass currentClazz = beanClass;
    boolean stopListeners = false;
    boolean stopDefaultListeners = false;
    do {
      Callback callback = null;
      List<XMethod> methods = currentClazz.getDeclaredMethods();
      final int size = methods.size();
      for ( int i = 0; i < size ; i++ ) {
        final XMethod xMethod = methods.get( i );
        if ( xMethod.isAnnotationPresent( annotation ) ) {
          Method method = reflectionManager.toMethod( xMethod );
          final String methodName = method.getName();
          if ( ! callbacksMethodNames.contains( methodName ) ) {
            //overridden method, remove the superclass overridden method
            if ( callback == null ) {
              callback = new BeanCallback( method );
              Class returnType = method.getReturnType();
              Class[] args = method.getParameterTypes();
              if ( returnType != Void.TYPE || args.length != 0 ) {
                throw new RuntimeException(
                    "Callback methods annotated on the bean class must return void and take no arguments: " + annotation
                        .getName() + " - " + xMethod
                );
              }
                            if (!method.isAccessible()) method.setAccessible(true);
                            LOG.debugf("Adding %s as %s callback for entity %s",
                                       methodName,
                                       annotation.getSimpleName(),
                                       beanClass.getName());
              callbacks.add( 0, callback ); //superclass first
              callbacksMethodNames.add( 0, methodName );
            }
            else {
              throw new PersistenceException(
                  "You can only annotate one callback method with "
                      + annotation.getName() + " in bean class: " + beanClass.getName()
              );
            }
          }
        }
      }
      if ( !stopListeners ) {
        getListeners( currentClazz, orderedListeners );
        stopListeners = currentClazz.isAnnotationPresent( ExcludeSuperclassListeners.class );
        stopDefaultListeners = currentClazz.isAnnotationPresent( ExcludeDefaultListeners.class );
      }

      do {
        currentClazz = currentClazz.getSuperclass();
      }
      while ( currentClazz != null
          && ! ( currentClazz.isAnnotationPresent( Entity.class )
          || currentClazz.isAnnotationPresent( MappedSuperclass.class ) )
          );
    }
    while ( currentClazz != null );

    //handle default listeners
    if ( ! stopDefaultListeners ) {
      List<Class> defaultListeners = (List<Class>) reflectionManager.getDefaults().get( EntityListeners.class );

      if ( defaultListeners != null ) {
        int defaultListenerSize = defaultListeners.size();
        for ( int i = defaultListenerSize - 1; i >= 0 ; i-- ) {
          orderedListeners.add( defaultListeners.get( i ) );
        }
      }
    }

    for ( Class listener : orderedListeners ) {
      Callback callback = null;
      if ( listener != null ) {
        XClass xListener = reflectionManager.toXClass( listener );
        callbacksMethodNames = new ArrayList<String>();
        List<XMethod> methods = xListener.getDeclaredMethods();
        final int size = methods.size();
        for ( int i = 0; i < size ; i++ ) {
          final XMethod xMethod = methods.get( i );
          if ( xMethod.isAnnotationPresent( annotation ) ) {
            final Method method = reflectionManager.toMethod( xMethod );
            final String methodName = method.getName();
            if ( ! callbacksMethodNames.contains( methodName ) ) {
              //overridden method, remove the superclass overridden method
              if ( callback == null ) {
                try {
                  callback = new ListenerCallback( method, listener.newInstance() );
                }
                catch (IllegalAccessException e) {
                  throw new PersistenceException(
                      "Unable to create instance of " + listener.getName()
                          + " as a listener of beanClass", e
                  );
                }
                catch (InstantiationException e) {
                  throw new PersistenceException(
                      "Unable to create instance of " + listener.getName()
                          + " as a listener of beanClass", e
                  );
                }
                Class returnType = method.getReturnType();
                Class[] args = method.getParameterTypes();
                if ( returnType != Void.TYPE || args.length != 1 ) {
                  throw new PersistenceException(
                      "Callback methods annotated in a listener bean class must return void and take one argument: " + annotation
                          .getName() + " - " + method
                  );
                }
                                if (!method.isAccessible()) method.setAccessible(true);
                                LOG.debugf("Adding %s as %s callback for entity %s",
                                           methodName,
                                           annotation.getSimpleName(),
                                           beanClass.getName());
                callbacks.add( 0, callback ); // listeners first
              }
              else {
                throw new PersistenceException(
                    "You can only annotate one callback method with "
                        + annotation.getName() + " in bean class: " + beanClass.getName() + " and callback listener: "
                        + listener.getName()
                );
              }
            }
          }
        }
      }
    }
    return callbacks.toArray( new Callback[ callbacks.size() ] );
  }

    public static Callback[] resolveCallbacks( Class<?> entityClass,
                                               Class<?> callbackClass,
                                               ClassLoaderService classLoaderService,
                                               EntityBinding binding ) {
        List<Callback> callbacks = new ArrayList<Callback>();
        for (JpaCallbackClass jpaCallbackClass : binding.getJpaCallbackClasses()) {
            Object listener = classLoaderService.classForName(jpaCallbackClass.getName());
            String methodName = jpaCallbackClass.getCallbackMethod( callbackClass );
            Callback callback = jpaCallbackClass.isListener() ?
                                createListenerCallback(entityClass, callbackClass, listener, methodName) :
                                createBeanCallback(callbackClass, methodName);
            LOG.debugf("Adding %s as %s callback for entity %s", methodName, callbackClass.getName(),
                       entityClass.getName());
            assert callback != null;
            callbacks.add(callback);
        }
        return callbacks.toArray(new Callback[callbacks.size()]);
    }

    private static Callback createListenerCallback( Class<?> entityClass,
                                                    Class<?> callbackClass,
                                                    Object listener,
                                                    String methodName ) {
        Class<?> callbackSuperclass = callbackClass.getSuperclass();
        if (callbackSuperclass != null) {
            Callback callback = createListenerCallback(entityClass, callbackSuperclass, listener, methodName);
            if (callback != null) return callback;
        }
        for (Method method : callbackClass.getDeclaredMethods()) {
            if (!method.getName().equals(methodName)) continue;
            Class<?>[] argTypes = method.getParameterTypes();
            if (argTypes.length != 1) continue;
            Class<?> argType = argTypes[0];
            if (argType != Object.class && argType != entityClass) continue;
            if (!method.isAccessible()) method.setAccessible(true);
            return new ListenerCallback(method, listener);
        }
        return null;
    }

    private static Callback createBeanCallback( Class<?> callbackClass,
                                                String methodName ) {
        Class<?> callbackSuperclass = callbackClass.getSuperclass();
        if (callbackSuperclass != null) {
            Callback callback = createBeanCallback(callbackSuperclass, methodName);
            if (callback != null) return callback;
        }
        for (Method method : callbackClass.getDeclaredMethods()) {
            if (!method.getName().equals(methodName)) continue;
            if (method.getParameterTypes().length != 0) continue;
            if (!method.isAccessible()) method.setAccessible(true);
            return new BeanCallback(method);
        }
        return null;
    }

  private static void getListeners(XClass currentClazz, List<Class> orderedListeners) {
    EntityListeners entityListeners = currentClazz.getAnnotation( EntityListeners.class );
    if ( entityListeners != null ) {
      Class[] classes = entityListeners.value();
      int size = classes.length;
      for ( int index = size - 1; index >= 0 ; index-- ) {
        orderedListeners.add( classes[index] );
      }
    }
    if ( useAnnotationAnnotatedByListener ) {
      Annotation[] annotations = currentClazz.getAnnotations();
      for ( Annotation annot : annotations ) {
        entityListeners = annot.getClass().getAnnotation( EntityListeners.class );
        if ( entityListeners != null ) {
          Class[] classes = entityListeners.value();
          int size = classes.length;
          for ( int index = size - 1; index >= 0 ; index-- ) {
            orderedListeners.add( classes[index] );
          }
        }
      }
    }
  }
}
TOP

Related Classes of org.hibernate.ejb.event.CallbackResolver

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.