Package net.sourceforge.javautil.interceptor

Source Code of net.sourceforge.javautil.interceptor.InterceptorCompiler$EnabledInterceptorBinding

package net.sourceforge.javautil.interceptor;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.interceptor.InterceptorBinding;
import javax.interceptor.Interceptors;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.util.ASMifierClassVisitor;

import net.sourceforge.javautil.bytecode.BytecodeCompiler;
import net.sourceforge.javautil.bytecode.IBytecodeFactory;
import net.sourceforge.javautil.bytecode.BytecodeCompiler.Version;
import net.sourceforge.javautil.bytecode.api.IBytecodeField;
import net.sourceforge.javautil.bytecode.api.IBytecodeResolvable;
import net.sourceforge.javautil.bytecode.api.MethodDescriptor;
import net.sourceforge.javautil.bytecode.api.TypeDescriptor;
import net.sourceforge.javautil.bytecode.api.TypeMemberAccess.Scope;
import net.sourceforge.javautil.bytecode.api.type.JavaClass;
import net.sourceforge.javautil.bytecode.api.type.JavaClassConcrete;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeBlock;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeConstructor;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeConstructorBase;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeContextMethod;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeMethod;
import net.sourceforge.javautil.common.CollectionUtil;
import net.sourceforge.javautil.common.VirtualArtifactUtil;
import net.sourceforge.javautil.common.io.IVirtualFile;
import net.sourceforge.javautil.common.reflection.ReflectionContext;
import net.sourceforge.javautil.common.reflection.cache.ClassCache;
import net.sourceforge.javautil.common.reflection.cache.ClassDescriptor;
import net.sourceforge.javautil.common.reflection.cache.ClassMethod;
import net.sourceforge.javautil.interceptor.annotation.Interceptorability;
import net.sourceforge.javautil.interceptor.asm.InterceptorHelper;
import net.sourceforge.javautil.interceptor.type.InterceptorInvocationHandler;
import net.sourceforge.javautil.interceptor.type.InterceptorProxyTypeAbstract;
import net.sourceforge.javautil.interceptor.type.InterceptorProxyTypeInterceptor;
import net.sourceforge.javautil.interceptor.type.cjc.InterceptorProxyConstructor;
import net.sourceforge.javautil.interceptor.type.cjc.InterceptorProxyMethod;
import net.sourceforge.javautil.interceptor.type.cjc.InterceptorProxyTypeCJC;
import net.sourceforge.javautil.interceptor.type.cjcw.InterceptorProxyTypeCJCW;

/**
* Interceptor proxy compiler based off the {@link IBytecodeFactory} API.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public class InterceptorCompiler extends BytecodeCompiler implements IInterceptorFactory {
 
  public enum InterceptorGranularity { PerClass, PerInstance }
 
  protected final Map<Class<?>, Class<?>> interceptorTypes = new HashMap<Class<?>, Class<?>>();
  protected final Map<Class<?>, Class<?>> interceptorWrapperTypes = new HashMap<Class<?>, Class<?>>();
  protected final Map<Class<?>, IInterceptorManager> defaultInterceptors = new HashMap<Class<?>, IInterceptorManager>();
 
  protected final Map<Class<? extends Annotation>, EnabledInterceptorBinding> interceptorBindings = new HashMap<Class<? extends Annotation>, EnabledInterceptorBinding>();
 
  protected String proxySuffix = "NETSFProxy";
 
  protected IInterceptorFactory interceptorFactory = this;
  protected InterceptorGranularity defaultGranularity = InterceptorGranularity.PerClass;
 
  public InterceptorCompiler(IBytecodeFactory factory) {
    super(factory);
  }

  public InterceptorCompiler(ClassLoader parent, IBytecodeFactory factory, Version defaultVersion) {
    super(parent, factory, defaultVersion);
  }

  public InterceptorCompiler(ClassLoader parent, IBytecodeFactory factory) {
    super(parent, factory);
  }
 
  /**
   * @return The suffix appended to class names for generated class proxies.
   */
  public String getProxySuffix() { return proxySuffix; }
  public void setProxySuffix(String proxySuffix) { this.proxySuffix = proxySuffix; }

  /**
   * @return The granularity for default {@link IInterceptorManager} creation.
   *
   * @see #getDefaultProxy(ClassLoader, IInterceptedInstanceWrapper, Class)
   * @see #getDefaultProxyInstance(Class, Object...)
   * @see #getDefaultWrapperProxyInstance(Class, IInterceptedInstanceWrapper, Object...)
   */
  public InterceptorGranularity getDefaultGranularity() { return defaultGranularity; }
  public void setDefaultGranularity(InterceptorGranularity defaultGranularity) { this.defaultGranularity = defaultGranularity; }

  /**
   * @return The factory used by this compiler for interceptor chain construction
   */
  public IInterceptorFactory getInterceptorFactory() { return interceptorFactory; }
 
  /**
   * This will not be retro-active on proxies already instantiated by this compiler.
   *
   * @param interceptorFactory The new factory to use
   */
  public void setInterceptorFactory(IInterceptorFactory interceptorFactory) {
    this.interceptorFactory = interceptorFactory;
    this.defaultInterceptors.clear();
  }

  public Object instantiateInterceptorLink(Class interceptorClass, IInterceptorLink next, Object intercepted) {
    return IInterceptorLink.class.isAssignableFrom(interceptorClass) ?
      ClassCache.getFor(interceptorClass).newInstance(next) :
      ClassCache.getFor(interceptorClass).newInstance();
  }

  public IInterceptorLink buildCustomChain(Object intercepted, Class... interceptorClasses) {
    return this.buildCustomChain(intercepted, new InterceptorLinkTarget(), interceptorClasses);
  }

  public IInterceptorLink buildCustomChain(Object intercepted, IInterceptorLink root, Class... interceptorClasses) {
    for (Class clazz : interceptorClasses) {
      Object interceptor = this.instantiateInterceptorLink(clazz, root, intercepted);
      if (interceptor instanceof IInterceptorLink) {
        root = (IInterceptorLink) interceptor;
      } else {
        root = new InterceptorLinkWrapper(root, interceptor);
      }
    }
    return root;
  }
 
  public IInterceptorLink buildDefaultChain(AnnotatedElement element, Object intercepted) {
    return this.buildDefaultChain(new InterceptorLinkTarget(), element, intercepted);
  }

  public IInterceptorLink buildDefaultChain(IInterceptorLink root, AnnotatedElement element, Object intercepted) {
    List<Class> aspects = new ArrayList<Class>();
   
    Interceptors declared = element.getAnnotation(Interceptors.class);
    if (declared != null) {
      aspects.addAll(Arrays.asList(declared.value()));
    }
   
    Set<Class<? extends Annotation>> bindings = this.collectBindings(element, new LinkedHashSet<Class<? extends Annotation>>());
    List<EnabledInterceptorBinding> enabled = new ArrayList<EnabledInterceptorBinding>();
    for (Class<? extends Annotation> binding : bindings) {
      if (this.interceptorBindings.containsKey(binding)) {
        if (!enabled.contains(this.interceptorBindings.get(binding)))
          enabled.add(this.interceptorBindings.get(binding));
      }
    }
   
    if (enabled.size() > 0) {
      if (enabled.size() > 1) Collections.sort(enabled);
      for (EnabledInterceptorBinding ei : enabled) {
        aspects.add(ei.interceptor);
      }
    }
   
    if (aspects.size() == 0) return root;
   
    return this.buildCustomChain(root, aspects.toArray(new Class[aspects.size()]));
  }

  public IInterceptorManager createInterceptor(Object intercepted, IInterceptorLink root) {
    return new InterceptorBase(this, root == null ? new InterceptorLinkTarget() : root);
  }

  public void bind(Class<?> interceptorClass) {
    if (interceptorClass.getAnnotation(javax.interceptor.Interceptor.class) != null) {
      for (Annotation annotation : interceptorClass.getAnnotations()) {
        InterceptorBinding ib = annotation.annotationType().getAnnotation(InterceptorBinding.class);
        if (ib != null) {
          if (this.interceptorBindings.containsKey(annotation.annotationType())) {
            throw new IllegalArgumentException("More than one interceptor defined with the same binding: " + annotation);
          }
          this.interceptorBindings.put(annotation.annotationType(), new EnabledInterceptorBinding(interceptorBindings.size(), interceptorClass));
        }
      }
    } else {
      throw new IllegalArgumentException("This is not an interceptor class");
    }
  }
 
  /**
   * @param annotated The annotated element
   * @param annotations The current set of annotations
   */
  protected Set<Class<? extends Annotation>> collectBindings (AnnotatedElement annotated, Set<Class<? extends Annotation>> annotations) {
    for (Annotation annotation : annotated.getAnnotations()) {
      if (annotation.annotationType().getAnnotation(InterceptorBinding.class) != null) {
        annotations.add(annotation.annotationType());
        this.collectBindings(annotation.annotationType(), annotations);
      }
    }
    return annotations;
  }

  /**
   * @param <T> The interface type
   * @param proxyClassLoader The class loader to use for creating the proxy
   * @param instance The instance to wrap, must implement the interface
   * @param iface The interface type class
   * @param interceptors The interceptors to use when proxied
   * @return The proxy instance
   */
  public <T> T getProxy (ClassLoader proxyClassLoader, IInterceptedInstanceWrapper<T> instance, Class<T> iface, IInterceptorManager interceptor) {
    List<IInterceptorManipulator> abilities = this.getInterceptorAbilities(iface);
    InterceptorInvocationHandler handler = new InterceptorInvocationHandler(instance, interceptor);
   
    T proxy = (T) Proxy.newProxyInstance(proxyClassLoader, new Class[] { iface }, handler);
    for (IInterceptorManipulator ability : abilities) {
      ability.manipulate(iface, interceptor, proxy, InterceptorInvocationHandler.getStateMap(handler));
    }
   
    return proxy;
  }
 
  /**
   * This will build the {@link IInterceptorManager} from defaults specified on the target.
   *
   * @see #getProxy(ClassLoader, Object, Class, IInterceptorManager)
   */
  public <T> T getDefaultProxy (ClassLoader proxyClassLoader, IInterceptedInstanceWrapper<T> instance, Class<T> iface) {
    return getProxy(proxyClassLoader, instance, iface, interceptorFactory.createInterceptor(instance, buildDefaultChain(instance.getClass(), instance)));
  }
 
  /**
   * This will build the {@link IInterceptorManager} from the specified classes.
   *
   * @see #getProxy(ClassLoader, Object, Class, IInterceptorManager)
   */
  public <T> T getProxy (ClassLoader proxyClassLoader, T instance, Class<T> iface, Class... interceptors) {
    return getProxy(proxyClassLoader, instance, iface, interceptorFactory.createInterceptor(instance, buildCustomChain(instance, interceptors)));
  }

  /**
   * This will wrap the instance in {@link InterceptedInstanceSimple}.
   *
   * @see #getProxy(ClassLoader, IInterceptedInstanceWrapper, Class, IInterceptorManager)
   */
  public <T> T getProxy (ClassLoader proxyClassLoader, T instance, Class<T> iface, IInterceptorManager interceptor) {
    return this.getProxy(proxyClassLoader, new InterceptedInstanceSimple<T>(instance), iface, interceptor);
  }
 
  /**
   * This will wrap the instance in {@link InterceptedInstanceSimple}.
   *
   * @see #getDefaultProxy(ClassLoader, IInterceptedInstanceWrapper, Class)
   */
  public <T> T getDefaultProxy (ClassLoader proxyClassLoader, T instance, Class<T> iface) {
    return this.getDefaultProxy(proxyClassLoader, new InterceptedInstanceSimple<T>(instance), iface);
  }
 
  /**
   * This will build the {@link IInterceptorManager} from the specified classes.
   *
   * @see #getProxy(ClassLoader, Object, Class, IInterceptorManager)
   */
  public <T> T getProxy (ClassLoader proxyClassLoader, IInterceptedInstanceWrapper<T> instance, Class<T> iface, Class... interceptors) {
    return getProxy(proxyClassLoader, instance, iface, interceptorFactory.createInterceptor(instance, buildCustomChain(instance, interceptors)));
  }
 
  /**
   * @param <T> The type of CONCRETE class
   * @param instance The instance to wrap
   * @param chain The interceptors to use
   * @param parameters The parameters to pass to the
   * @return An instance of the proxy class wrapping the instance passed
   *
   * @see #getProxy(Class)
   */
  public <T> T getProxyInstance (Class<T> type, IInterceptorManager interceptor, Object... parameters) throws IOException {
    Class<? extends T> proxyClass = this.getProxyClass(type);
    ClassDescriptor<? extends T> pcDesc = ClassCache.getFor(proxyClass);
   
    T instance =  pcDesc.newInstance(CollectionUtil.insert(parameters, 0, interceptor));
    if (interceptor == null) {
      ClassMethod method = ClassCache.getFor(proxyClass).findMethod("set$Interceptor", IInterceptorManager.class);
     
      ReflectionContext.getReflectionManager().ensureAccesssibility(method.getJavaMember());
      method.invoke(instance, this.getDefaultInterceptorManager(instance, type));
    }
    return instance;
  }
 
  /**
   * This will create the {@link IInterceptorManager} from the specified classes
   *
   * @see #getProxyInstance(Object, IInterceptorLink, Object...)
   */
  public <T> T getProxyInstance (Class<T> type, Class[] interceptors, Object... parameters) throws IOException {
    return getProxyInstance(type, interceptorFactory.createInterceptor(null, buildCustomChain(null, interceptors)), parameters);
  }
 
  /**
   * This will create the {@link IInterceptorManager} from the class specified interceptors.
   *
   * @see #getProxyInstance(Object, IInterceptorLink, Object...)
   */
  public <T> T getDefaultProxyInstance (Class<T> type, Object... parameters) throws IOException {
    return getProxyInstance(type, (IInterceptorManager) null, parameters);
  }
 
  /**
   * @param <T> The type of proxy
   * @param type The class of the type
   * @param instance The instance wrapper
   * @param interceptor The interceptor to use for this proxy instance
   * @param parameters The parameters to pass to the constructor
   * @return The proxy instance
   */
  public <T> T getWrapperProxyInstance (Class<T> type, IInterceptedInstanceWrapper<T> instance, IInterceptorManager interceptor, Object... parameters) throws IOException {
    Class<? extends T> proxyClass = this.getWrapperProxyClass(type);
    ClassDescriptor<? extends T> pcDesc = ClassCache.getFor(proxyClass);
   
    return pcDesc.newInstance(CollectionUtil.insert(parameters, 0, interceptor, instance));
  }
 
  /**
   * Create an interceptor using the passed interceptor classes.
   *
   * @param interceptors The classes used to create the interceptor chain.
   *
   * @see #getWrapperProxyInstance(Class, IInterceptedInstanceWrapper, IInterceptorManager, Object...)
   * @see #buildCustomChain(Class...)
   */
  public <T> T getWrapperProxyInstance (Class<T> type, IInterceptedInstanceWrapper<T> instance, Class[] interceptors, Object... parameters) throws IOException {
    return getWrapperProxyInstance(type, instance, interceptorFactory.createInterceptor(instance, buildCustomChain(instance, interceptors)), parameters);
  }
 
  /**
   * Use the default interceptors for the proxy.
   *
   * @see #getWrapperProxyInstance(Class, IInterceptedInstanceWrapper, IInterceptorManager, Object...)
   */
  public <T> T getDefaultWrapperProxyInstance (Class<T> type, IInterceptedInstanceWrapper<T> instance, Object... parameters) throws IOException {
    return getWrapperProxyInstance(type, instance, this.getDefaultInterceptorManager(instance, type), parameters);
  }

  /**
   * This uses {@link InterceptedInstanceSimple} to wrap the concrete instance.
   *
   * @see #getWrapperProxyInstance(Class, IInterceptedInstanceWrapper, IInterceptorManager, Object...)
   */
  public <T> T getWrapperProxyInstance (Class<T> type, T instance, IInterceptorManager interceptor, Object... parameters) throws IOException {
    return this.getWrapperProxyInstance(type, new InterceptedInstanceSimple<T>(instance), interceptor, parameters);
  }
 
  /**
   * This uses {@link InterceptedInstanceSimple} to wrap the concrete instance.
   *
   * @see #getWrapperProxyInstance(Class, IInterceptedInstanceWrapper, Class[], Object...)
   */
  public <T> T getWrapperProxyInstance (Class<T> type, T instance, Class[] interceptors, Object... parameters) throws IOException {
    return getWrapperProxyInstance(type, new InterceptedInstanceSimple<T>(instance), interceptors, parameters);
  }
 
  /**
   * This uses {@link InterceptedInstanceSimple} to wrap the concrete instance.
   *
   * @see #getDefaultWrapperProxyInstance(Class, IInterceptedInstanceWrapper, Object...)
   */
  public <T> T getDefaultWrapperProxyInstance (Class<T> type, T instance, Object... parameters) throws IOException {
    return this.getDefaultWrapperProxyInstance(type, new InterceptedInstanceSimple<T>(instance), parameters);
  }
 
  /**
   * NOTE: It is preferrable that the class provide a no-argument constructor.
   *
   * @param <T> The type of CONCRETE class
   * @param type The type's class
   * @return A class of the same 'type', an extended class, for proxy creation with all constructors accepting two inserted arguments
   *   at the beginning of the parameter list of each constructor, the first of the actual type this is extending and the second
   *   an array of {@link IInterceptorLink}'s.
   *
   * @see #getProxyInstance(Object, IInterceptorLink[], Object...)
   */
  public synchronized <T> Class<? extends T> getProxyClass (Class<T> type) throws IOException {
    if (interceptorTypes.containsKey(type)) return (Class<? extends T>) interceptorTypes.get(type);
   
    Class<? extends T> proxyClass = compile(this.getProxyClassTemplate(type, false));
    this.interceptorTypes.put(type, proxyClass);
   
    return proxyClass;
  }
 
  /**
   * NOTE: It is preferrable that the class provide a no-argument constructor.
   *
   * @param <T> The type of CONCRETE class
   * @param type The type's class
   * @return A class of the same 'type', an extended class, for proxy creation with all constructors accepting two inserted arguments
   *   at the beginning of the parameter list of each constructor, the first of the actual type this is extending and the second
   *   an array of {@link IInterceptorLink}'s.
   *
   * @see #getProxyInstance(Object, IInterceptorLink[], Object...)
   */
  public synchronized <T> Class<? extends T> getWrapperProxyClass (Class<T> type) throws IOException {
    if (interceptorWrapperTypes.containsKey(type)) return (Class<? extends T>) interceptorWrapperTypes.get(type);
   
    Class<? extends T> proxyClass = compile(this.getProxyClassTemplate(type, true));
    this.interceptorWrapperTypes.put(type, proxyClass);
   
    return proxyClass;
  }
 
  /**
   * @param type The type the template is for
   * @return The concrete class template
   */
  protected JavaClassConcrete getProxyClassTemplate (Class<?> type, boolean wrapper) {
    IBytecodeResolvable resolved = getPool().resolve(type.getName());
    if (resolved.isFinal() || resolved.isAbstract())
      throw new IllegalArgumentException("Cannot create class based proxies for final/non static/abstract classes");
   
    final List<IInterceptorManipulator> abilities = this.getInterceptorAbilities(type);
    InterceptorProxyTypeAbstract proxy = wrapper ?
      new InterceptorProxyTypeCJCW(this, abilities, type, type.getName() + "$CJCW$" + proxySuffix) :
      new InterceptorProxyTypeCJC(this, abilities, type, type.getName() + "$CJC$" + proxySuffix);
   
    proxy.addProxyConstructors();
    proxy.addProxyMethods();
    proxy.addProxyAbilities();

    return proxy;
  }
 
  /**
   * @param type The type abilities are for
   * @return The list of abilities for this type
   */
  protected List<IInterceptorManipulator> getInterceptorAbilities (Class type) {
    Set<Class<? extends IInterceptorManipulator>> abilityTypes = new LinkedHashSet<Class<? extends IInterceptorManipulator>>();
    this.findInterceptorAbilities(type, abilityTypes);
   
    List<IInterceptorManipulator> abilities = new ArrayList<IInterceptorManipulator>();
    for (Class<? extends IInterceptorManipulator> atype : abilityTypes) {
      abilities.add(ClassCache.getFor(atype).newInstance());
    }
    return abilities;
  }
 
  /**
   * Recursive loop based search for annotations that added {@link IInterceptorManipulator}'s to a particular proxy class.
   *
   * @param type The type in question
   * @param abilities The unique set of abilities for the particular type
   */
  protected void findInterceptorAbilities (Class type, Set<Class<? extends IInterceptorManipulator>> abilityTypes) {
    for (Annotation annotation : type.getAnnotations()) {
      if (annotation.annotationType().getPackage().getName().startsWith("java")) continue;
     
      Interceptorability ability = annotation.annotationType().getAnnotation(Interceptorability.class);
      if (ability != null) {
        abilityTypes.add(ability.value());
      }
     
      this.findInterceptorAbilities(annotation.annotationType(), abilityTypes);
    }
  }
 
  /**
   * @param instance The instance in question
   * @param type The type of interceptor
   * @return The manager for the particular type
   *
   * @see #getDefaultGranularity()
   */
  protected IInterceptorManager getDefaultInterceptorManager (Object instance, Class type) {
    if (this.defaultGranularity == InterceptorGranularity.PerInstance) {
      return interceptorFactory.createInterceptor(instance, buildDefaultChain(type, instance));
    } else {
      IInterceptorManager interceptor = this.defaultInterceptors.get(type);
      if (interceptor == null)
        interceptor = interceptorFactory.createInterceptor(instance, buildDefaultChain(type, instance));
      return interceptor;
    }
  }
 
  /**
   * Wrapper for enabled interceptors allowing interceptor ordering.
   *
   * @author elponderador
   * @author $Author$
   * @version $Id$
   */
  protected class EnabledInterceptorBinding implements Comparable<EnabledInterceptorBinding> {
   
    protected final int index;
    protected final Class<?> interceptor;
   
    public EnabledInterceptorBinding(int index, Class<?> interceptor) {
      this.index = index;
      this.interceptor = interceptor;
    }

    public int compareTo(EnabledInterceptorBinding o) {
      int compare = o.index;
      return index == compare ? 0 : (index > compare ? 1 : -1);
    }
   
  }
 
}
TOP

Related Classes of net.sourceforge.javautil.interceptor.InterceptorCompiler$EnabledInterceptorBinding

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.