/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source 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, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.config.gen; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.PostConstruct; import javax.enterprise.inject.Stereotype; import javax.enterprise.inject.spi.AnnotatedMethod; import javax.enterprise.inject.spi.InterceptionType; import javax.enterprise.inject.spi.Interceptor; import javax.enterprise.util.Nonbinding; import javax.inject.Inject; import javax.interceptor.AroundInvoke; import javax.interceptor.InterceptorBinding; import com.caucho.config.ConfigException; import com.caucho.config.inject.DependentCreationalContext; import com.caucho.config.inject.InjectManager; import com.caucho.config.inject.InterceptorBean; import com.caucho.config.inject.InterceptorRuntimeBean; import com.caucho.config.inject.InterceptorSelfBean; import com.caucho.config.reflect.AnnotatedTypeUtil; import com.caucho.inject.Module; import com.caucho.java.JavaWriter; /** * Represents the interception */ @Module public class InterceptorGenerator<X> extends AbstractAspectGenerator<X> { private static final Logger log = Logger.getLogger(InterceptorGenerator.class.getName()); private static final String INTERCEPTOR_MAP = "caucho.interceptor.map"; private static final Method _nullMethod; private InterceptorFactory<X> _factory; private String _uniqueName; private String _chainName; private boolean _isChainNew; // private boolean _isExcludeDefaultInterceptors; // private boolean _isExcludeClassInterceptors; private InterceptionType _interceptionType = InterceptionType.AROUND_INVOKE; private ArrayList<Annotation> _interceptorBinding = new ArrayList<Annotation>(); private ArrayList<Class<?>> _interceptors = new ArrayList<Class<?>>(); private boolean _isEpilogue; private InterceptionBinding _bindingEntry; // map from the interceptor class to the local variable for the interceptor private HashMap<Interceptor<?>, String> _interceptorVarMap = new HashMap<Interceptor<?>, String>(); // interceptors we're responsible for initializing private ArrayList<Class<?>> _ownInterceptors = new ArrayList<Class<?>>(); // decorators private HashSet<Class<?>> _decoratorSet; private final String _decoratorClass = "__caucho_decorator_class"; private final String _decoratorBeansVar = "__caucho_decorator_beans"; private final String _decoratorIndexVar = "__caucho_delegates"; private final String _decoratorLocalVar = _decoratorClass + "_tl"; private final String _delegateVar = "__caucho_delegate"; private String _decoratorSetName; public InterceptorGenerator(InterceptorFactory<X> factory, AnnotatedMethod<? super X> method, AspectGenerator<X> next, InterceptionType type, HashSet<Class<?>> methodInterceptors, HashMap<Class<?>, Annotation> methodInterceptorMap, HashSet<Class<?>> decoratorSet, boolean isExcludeClassInterceptors) { super(factory, method, next); _factory = factory; _interceptionType = type; if (methodInterceptors != null) _interceptors.addAll(methodInterceptors); if (methodInterceptorMap != null) _interceptorBinding.addAll(methodInterceptorMap.values()); _decoratorSet = decoratorSet; introspect(); } public InterceptorGenerator(InterceptorFactory<X> factory, HashSet<Class<?>> lifecycleInterceptors, InterceptionType type) { super(factory, null, (NullGenerator) NullGenerator.NULL); _factory = factory; if (lifecycleInterceptors != null) _interceptors.addAll(lifecycleInterceptors); _interceptionType = type; if (factory.getClassInterceptorBindings() != null) _interceptorBinding.addAll(factory.getClassInterceptorBindings().values()); _isEpilogue = true; } public ArrayList<Class<?>> getInterceptors() { return _interceptors; } private AnnotatedMethod<? super X> getAroundInvokeMethod() { return _factory.getAroundInvokeMethod(); } private boolean isProxy() { return _factory.getAspectBeanFactory().isProxy(); } // // introspection // /** * Introspects the @Interceptors annotation on the method and the class. */ private void introspect() { /* if (implMethod.isAnnotationPresent(Inject.class) || implMethod.isAnnotationPresent(PostConstruct.class)) { // ioc/0a23, ioc/0c57 return; } */ introspectInterceptors(); // introspectDefaults(); } private void introspectInterceptors() { } // // bean instance generation // public void generateClassPostConstruct(JavaWriter out, HashMap<String, Object> map) throws IOException { super.generatePostConstruct(out, map); _uniqueName = (String) map.get("caucho.interceptor.postConstructName"); generateInterceptorCall(out, map); map.put("caucho.interceptor.postConstructName", _uniqueName); } public void generateClassPreDestroy(JavaWriter out, HashMap<String, Object> map) throws IOException { super.generatePreDestroy(out, map); _uniqueName = (String) map.get("caucho.interceptor.preDestroyName"); generateInterceptorCall(out, map); map.put("caucho.interceptor.preDestroyName", _uniqueName); } @Override public void generateEpilogue(JavaWriter out, HashMap<String, Object> map) throws IOException { super.generateEpilogue(out, map); String key = null; if (_interceptionType == InterceptionType.POST_CONSTRUCT) key = "caucho.interceptor.postConstructName"; else if (_interceptionType == InterceptionType.PRE_DESTROY) key = "caucho.interceptor.preDestroyName"; _uniqueName = (String) map.get(key); /* if (_uniqueName == null) return; */ generateBeanPrologue(out, map); generateMethodPrologue(out, map); out.println("static {"); out.pushDepth(); out.println("try {"); out.pushDepth(); out.print(CandiUtil.class.getName()); out.print(".createInterceptors(__caucho_manager, __caucho_interceptor_beans"); for (int i = 0; i < _interceptorBinding.size(); i++) { out.print(", "); generateAnnotation(out, _interceptorBinding.get(i)); } out.println(");"); if (isPassivating()) { String beanClassName = getFactory().getAspectBeanFactory().getInstanceClassName(); out.println(); out.print("com.caucho.config.gen.CandiUtil.validatePassivating("); out.print(beanClassName + ".class, "); out.println("__caucho_interceptor_beans);"); } out.popDepth(); out.println("} catch (Exception e) {"); out.println(" __caucho_log.log(java.util.logging.Level.WARNING, e.toString(), e);"); out.println(" __caucho_exception = com.caucho.config.ConfigException.create(e);"); out.println("}"); out.popDepth(); out.println("}"); map.put(key, _uniqueName); } private boolean isPassivating() { if (_factory.isPassivating()) return true; else if (_factory.isStateful()) return _interceptorBinding.size() > 0 || _decoratorSet != null; else return false; } /** * Generates the prologue for the bean instance. */ @Override public void generateBeanPrologue(JavaWriter out, HashMap<String,Object> map) throws IOException { super.generateBeanPrologue(out, map); if (map.get("__caucho_interceptor_objects") == null) { map.put("__caucho_interceptor_objects", true); out.println(); out.print("private transient Object []"); out.println("__caucho_interceptor_objects;"); out.println("Object []_caucho_getInterceptorObjects()"); out.println("{ return __caucho_interceptor_objects; }"); } generateBeanInterceptorChain(out, map); // if (getMethod() != null) generateTail(out); /* else generateNullTail(out); */ } @Override public void generateBeanConstructor(JavaWriter out, HashMap<String,Object> map) throws IOException { super.generateBeanConstructor(out, map); /* if (hasInterceptor()) { generateInterceptorBeanConstructor(out, map); } */ if (hasDecorator()) { generateDecoratorBeanConstructor(out, map); } } @Override public void generateInject(JavaWriter out, HashMap<String,Object> map) throws IOException { super.generateInject(out, map); if (hasInterceptor()) { generateInterceptorBeanInject(out, map); } if (hasDecorator()) { generateDecoratorBeanInject(out, map); } } @Override public void generateProxyConstructor(JavaWriter out, HashMap<String,Object> map) throws IOException { super.generateProxyConstructor(out, map); if (hasDecorator()) { // generateDecoratorProxyConstructor(out, map); } } private void generateInterceptorBeanInject(JavaWriter out, HashMap<String,Object> map) throws IOException { if (map.get("interceptor_object_init") != null) return; map.put("interceptor_object_init", true); out.println("int size = __caucho_interceptor_beans.size();"); out.println("if (interceptors == null) {"); out.pushDepth(); out.println("interceptors = new Object[size];"); out.println(); // XXX: should be parent bean // out.println(" = __caucho_manager.createCreationalContext(null);"); out.println(); out.println("for (int i = 0; i < size; i++) {"); out.pushDepth(); out.println("javax.enterprise.inject.spi.Bean bean"); out.println(" = __caucho_interceptor_beans.get(i);"); out.println("javax.enterprise.context.spi.CreationalContext env"); out.println(" = new " + DependentCreationalContext.class.getName() + "(bean, parentEnv, null);"); out.print("interceptors[i] = "); out.println("__caucho_manager.getReference(bean, bean.getBeanClass(), env);"); // ejb/6032 out.print("if (interceptors[i] == null && (bean instanceof "); out.printClass(InterceptorSelfBean.class); out.println("))"); out.print(" interceptors[i] = "); out.print(getBeanFactory().getBeanInstance()); out.println(";"); out.println("else if (interceptors[i] == null)"); out.println(" throw new NullPointerException(String.valueOf(bean));"); out.popDepth(); out.println("}"); out.popDepth(); out.println("}"); out.println("__caucho_interceptor_objects = interceptors;"); for (Class<?> iClass : _ownInterceptors) { String var = _interceptorVarMap.get(iClass); out.println("if (" + var + "_f == null)"); out.println(" " + var + "_f = __caucho_manager.createTransient(" + iClass.getName() + ".class);"); out.print(var + " = ("); out.printClass(iClass); out.println(") __caucho_manager.getInstance(" + var + "_f);"); } } // XXX This map is really a Map<String, Object>, so putting in an // InterceptionBinding seems wrong. Also, it doesn't discriminate the // chainName -- see the generated code for test1() in ejb/10a5 private void generateBeanInterceptorChain(JavaWriter out, HashMap<String,Object> map) throws IOException { _chainName = getChainName(out, map); if (_interceptors.size() > 0) { List<Class<?>> interceptors = (List<Class<?>>) map.get("@Interceptors"); if (interceptors == null) interceptors = new ArrayList<Class<?>>(); // int []indexChain = new int[_interceptors.size()]; } } // // business method interception // /** * Generates the prologue for a method. */ @Override public void generateMethodPrologue(JavaWriter out, HashMap<String,Object> map) throws IOException { super.generateMethodPrologue(out, map); if (map.get("__caucho_manager") == null) { map.put("__caucho_manager", true); out.println(); out.print("private static "); out.printClass(InjectManager.class); out.println(" __caucho_manager"); out.print(" = "); out.printClass(InjectManager.class); out.println(".create();"); } /* XXX: if (! _isExcludeDefaultInterceptors) _interceptors.addAll(_view.getBean().getDefaultInterceptors()); */ if (hasInterceptor()) generateInterceptorMethodPrologue(out, map); if (hasDecorator()) generateDecoratorMethodPrologue(out, map); // _bizMethod.generateInterceptorTarget(out); } @Override public void generatePreTry(JavaWriter out) throws IOException { // ejb/12a0 super.generatePreTry(out); if (hasDecorator()) { generateDecoratorPreTry(out); } } @Override public void generatePreCall(JavaWriter out) throws IOException { if (hasDecorator()) { generateDecoratorPreCall(out); } } @Override public void generateCall(JavaWriter out) throws IOException { if (hasInterceptor()) { HashMap<String,Object> map = null; generateInterceptorCall(out, map); } else if (hasDecorator()) { generateDecoratorCall(out); } else { throw new IllegalStateException(toString()); } } @Override public void generateFinally(JavaWriter out) throws IOException { // server/12a0 super.generateFinally(out); if (hasDecorator()) { generateDecoratorFinally(out); } } // // interceptor // @Override protected Method getJavaMethod() { AnnotatedMethod<? super X> method = getMethod(); if (method != null) return method.getJavaMember(); else return _nullMethod; } private void generateInterceptorMethodPrologue(JavaWriter out, HashMap<String,Object> map) throws IOException { if (map.get("__caucho_interceptor_beans") == null) { map.put("__caucho_interceptor_beans", true); out.println(); out.print("private static final "); out.print("java.util.ArrayList<"); out.printClass(InterceptorRuntimeBean.class); out.println("<?>> __caucho_interceptor_static_beans"); out.print(" = new java.util.ArrayList<"); out.printClass(InterceptorRuntimeBean.class); out.println("<?>>();"); out.println(); out.print("private static final "); out.print("java.util.ArrayList<"); out.printClass(Interceptor.class); out.println("<?>> __caucho_interceptor_beans"); out.print(" = new java.util.ArrayList<"); out.printClass(Interceptor.class); out.println("<?>>();"); } generateInterceptorMethod(out, map); generateInterceptorChain(out, map); } private void generateInterceptorMethod(JavaWriter out, HashMap<String,Object> map) throws IOException { Method javaMethod = getJavaMethod(); out.println(); out.println("private static java.lang.reflect.Method " + getUniqueName(out) + "_method;"); out.println("private static java.lang.reflect.Method " + getUniqueName(out) + "_implMethod;"); boolean isAroundInvokePrologue = false; if (getAroundInvokeMethod() != null && map.get("ejb.around-invoke") == null) { isAroundInvokePrologue = true; map.put("ejb.around-invoke", "_caucho_aroundInvokeMethod"); out.println( "private static java.lang.reflect.Method __caucho_aroundInvokeMethod;"); } out.println(); out.println("static {"); out.pushDepth(); out.println("try {"); out.pushDepth(); out.print(getUniqueName(out) + "_method = "); String declaringClassName = javaMethod.getDeclaringClass().getName(); if (hasDecorator()) { // ioc/0c22 declaringClassName = _decoratorSet.iterator().next().getName(); } generateGetMethod(out, declaringClassName, javaMethod.getName(), javaMethod.getParameterTypes()); out.println(";"); out.println(getUniqueName(out) + "_method.setAccessible(true);"); String superMethodName = getSuperMethodName(); out.print(getUniqueName(out) + "_implMethod = "); String className; if (javaMethod.getDeclaringClass().equals(getClass())) { className = InterceptorGenerator.class.getName(); superMethodName = javaMethod.getName(); } else { // ioc/0c22 // className = getBeanFactory().getInstanceClassName(); className = declaringClassName; // ejb/6030 vs ioc/0c00 if (getBeanFactory().isProxy()) { superMethodName = javaMethod.getName(); } } // ejb/1061 if (Modifier.isStatic(javaMethod.getModifiers())) { generateGetMethod(out, javaMethod.getDeclaringClass().getName(), javaMethod.getName(), javaMethod.getParameterTypes()); } else { generateGetMethod(out, className, superMethodName, javaMethod.getParameterTypes()); } out.println(";"); /* out.print(getUniqueName(out) + "_implMethod = "); out.println(getUniqueName(out) + "_method;"); out.println(getUniqueName(out) + "_implMethod.setAccessible(true);"); */ if (isAroundInvokePrologue) { AnnotatedMethod<? super X> aroundInvoke = getAroundInvokeMethod(); out.print("__caucho_aroundInvokeMethod = "); generateGetMethod(out, aroundInvoke.getJavaMember().getDeclaringClass().getName(), aroundInvoke.getJavaMember().getName(), aroundInvoke.getJavaMember().getParameterTypes()); out.println(";"); out.println("__caucho_aroundInvokeMethod.setAccessible(true);"); } out.popDepth(); out.println("} catch (Exception e) {"); out.println(" __caucho_log.log(java.util.logging.Level.WARNING, e.toString(), e);"); out.println(" __caucho_exception = com.caucho.config.ConfigException.create(e);"); out.println("}"); out.popDepth(); out.println("}"); } private String getSuperMethodName() { Method javaMethod = getJavaMethod(); String declName = javaMethod.getDeclaringClass().getSimpleName(); if (hasDecorator()) return "__caucho_" + javaMethod.getName() + "_decorator"; else if (isProxy()) return javaMethod.getName(); else { return ("__caucho_" + declName + "_" + javaMethod.getName() + "_" + _interceptionType); } } private String getChainName(JavaWriter out, HashMap<String,Object> map) { if (_chainName != null) return _chainName; HashMap bindingMap = (HashMap) map.get(INTERCEPTOR_MAP); if (bindingMap == null) { bindingMap = new HashMap(); map.put(INTERCEPTOR_MAP, bindingMap); } _bindingEntry = new InterceptionBinding(_interceptionType, _interceptorBinding, _interceptors); _chainName = (String) bindingMap.get(_bindingEntry); if (_chainName != null) { return _chainName; } _chainName = getUniqueName(out); _isChainNew = true; bindingMap.put(_bindingEntry, _chainName); return _chainName; } private void generateInterceptorChain(JavaWriter out, HashMap<String,Object> map) throws IOException { String chainName = getChainName(out, map); if (! _isChainNew) return; if (_interceptors.size() > 0) { List<Class<?>> interceptors = (List<Class<?>>) map.get("@Interceptors"); if (interceptors == null) { interceptors = new ArrayList<Class<?>>(); map.put("@Interceptors", interceptors); } ArrayList<Integer> indexChain = new ArrayList<Integer>(); out.println("static {"); out.pushDepth(); for (int i = 0; i < _interceptors.size(); i++) { Class<?> iClass = _interceptors.get(i); int index = interceptors.indexOf(iClass); if (index > -1) { indexChain.add(index); } else { indexChain.add(interceptors.size()); interceptors.add(iClass); if (iClass.isAssignableFrom(getJavaClass())) { out.print("__caucho_interceptor_static_beans.add(new "); out.printClass(InterceptorSelfBean.class); out.print("("); //out.printClass(iClass); out.printClass(getJavaClass()); out.println(".class));"); } else { out.print("__caucho_interceptor_static_beans.add(new "); out.printClass(InterceptorBean.class); out.print("("); out.printClass(iClass); out.println(".class));"); } } } out.popDepth(); out.println("}"); out.println(); out.print("private static int []" + chainName + "_objectIndexStaticChain = new int[] {"); for (int i : indexChain) { out.print(i); out.print(','); } out.println("};"); } else { out.println("private static int []" + chainName + "_objectIndexStaticChain;"); } out.println("private static int []" + chainName + "_objectIndexChain;"); out.println("private static javax.enterprise.inject.spi.Interceptor []" + chainName + "_methodChain;"); out.println(); out.println("static {"); out.pushDepth(); out.println("try {"); out.pushDepth(); generateMethodChain(out, map); out.popDepth(); out.println("} catch (Exception e) {"); out.println(" __caucho_log.log(java.util.logging.Level.WARNING, e.toString(), e);"); out.println(" __caucho_exception = com.caucho.config.ConfigException.create(e);"); out.println("}"); out.popDepth(); out.println("}"); } private void generateMethodChain(JavaWriter out, HashMap<String,Object> map) throws IOException { String chainName = getChainName(out, map); out.println(chainName + "_objectIndexChain ="); out.println(" com.caucho.config.gen.CandiUtil.createInterceptors("); out.println(" __caucho_manager,"); out.println(" __caucho_interceptor_static_beans,"); out.println(" __caucho_interceptor_beans,"); out.println(" " + chainName+ "_objectIndexStaticChain,"); out.print(" " + InterceptionType.class.getName() + "." + _interceptionType); for (int i = 0; i < _interceptorBinding.size(); i++) { out.println(","); out.pushDepth(); out.pushDepth(); generateAnnotation(out, _interceptorBinding.get(i)); out.popDepth(); out.popDepth(); } out.println(");"); out.println(); out.println(chainName + "_methodChain = "); out.println(" com.caucho.config.gen.CandiUtil.createMethods("); out.println(" __caucho_interceptor_beans,"); out.println(" " + InterceptionType.class.getName() + "." + _interceptionType + ","); out.println(" " + chainName + "_objectIndexChain);"); if (isPassivating()) { String beanClassName = getFactory().getAspectBeanFactory().getInstanceClassName(); out.println(); out.print("com.caucho.config.gen.CandiUtil.validatePassivating("); out.print(beanClassName + ".class, "); out.println("__caucho_interceptor_beans);"); } } private void generateInterceptorCall(JavaWriter out, HashMap<String,Object> map) throws IOException { Method javaMethod = getJavaMethod(); String uniqueName = getUniqueName(out); String chainName = getChainName(out, map); out.println("try {"); out.pushDepth(); if (javaMethod != null && ! void.class.equals(javaMethod.getReturnType())) { out.print("result = ("); printCastClass(out, getMethod().getBaseType()); out.print(") "); } out.print("new "); out.printClass(CandiInvocationContext.class); out.println("("); out.pushDepth(); out.pushDepth(); out.printClass(InterceptionType.class); out.println("." + _interceptionType + ", "); if (hasDecorator()) out.print("delegate"); else out.print(_factory.getAspectBeanFactory().getInterceptorInstance()); out.println(", "); // generateThis(out); if (_interceptionType == InterceptionType.AROUND_INVOKE) out.println(uniqueName + "_method, "); else out.println("null, "); // generateThis(out); out.println(uniqueName + "_implMethod, "); // generateThis(out); out.println(chainName + "_methodChain, "); out.print(_factory.getAspectBeanFactory().getBeanInfo()); out.println("._caucho_getInterceptorObjects(), "); // generateThis(out); out.println(chainName + "_objectIndexChain, "); Class<?>[] paramTypes = (javaMethod != null ? javaMethod.getParameterTypes() : null); if (getMethod() == null || getMethod().isAnnotationPresent(PostConstruct.class)) { out.println("null"); } else if (paramTypes == null || paramTypes.length == 0) { out.println("com.caucho.config.gen.CandiUtil.NULL_OBJECT_ARRAY"); } else { out.print("new Object[] { "); for (int i = 0; i < javaMethod.getParameterTypes().length; i++) { out.print("a" + i + ", "); } out.println("}"); } out.println(").proceed();"); out.popDepth(); out.popDepth(); /* // super.generatePostCall(out); if (! void.class.equals(_implMethod.getReturnType())) { out.println("return result;"); } */ out.popDepth(); out.println("} catch (RuntimeException e) {"); out.println(" throw e;"); boolean isException = false; Class<?>[] exnList; if (javaMethod != null) exnList = javaMethod.getExceptionTypes(); else exnList = new Class<?>[0]; for (Class<?> cl : exnList) { if (RuntimeException.class.isAssignableFrom(cl)) continue; if (! isMostGeneralException(exnList, cl)) continue; if (cl.isAssignableFrom(Exception.class)) isException = true; out.println("} catch (" + cl.getName() + " e) {"); out.println(" throw e;"); } if (! isException) { out.println("} catch (Exception e) {"); out.println(" throw new RuntimeException(e);"); } out.println("}"); } // // decorator method // private void generateDecoratorBeanConstructor(JavaWriter out, HashMap<String,Object> map) throws IOException { } private void generateDecoratorBeanInject(JavaWriter out, HashMap<String,Object> map) throws IOException { if (_decoratorSet == null) return; out.println("__caucho_delegates = delegates;"); } private void generateDecoratorMethodPrologue(JavaWriter out, HashMap<String,Object> map) throws IOException { generateDecoratorClass(out, map); String decoratorSetName = getDecoratorSetName(out, map); if (hasInterceptor()) generateDecoratorMethod(out); if (map.get("decorator_bean_" + decoratorSetName) != null) return; map.put("decorator_bean_" + decoratorSetName, true); if (map.get("decorator_delegate_decl") == null) { map.put("decorator_delegate_decl", true); out.print("private static "); out.print(_decoratorClass); out.println(" " + _delegateVar + ";"); out.println(); out.println("private static " + "java.util.List<javax.enterprise.inject.spi.Decorator<?>> " + _decoratorBeansVar + ";"); out.println(); out.println("static final ThreadLocal<" + _decoratorClass + "> " + _decoratorLocalVar); out.println(" = new ThreadLocal<" + _decoratorClass + ">();"); out.println(); out.println("private transient Object [] " + _decoratorIndexVar + ";"); out.println(); out.println("final Object []__caucho_getDelegates()"); out.println("{"); out.println(" return " + _decoratorIndexVar + ";"); out.println("}"); generateDecoratorInit(out); } } private void generateDecoratorInit(JavaWriter out) throws IOException { out.println(); out.println("public static Object __caucho_decorator_init()"); out.println("{"); out.pushDepth(); out.println("if (__caucho_delegate == null)"); out.println(" __caucho_delegate = new __caucho_decorator_class(0, null, null);"); out.println(); out.println("return __caucho_delegate;"); out.popDepth(); out.println("}"); } private void generateDecoratorClass(JavaWriter out, HashMap<String,Object> map) throws IOException { if (map.get("decorator_class_decl") != null) return; map.put("decorator_class_decl", true); String className = _decoratorClass; ArrayList<Method> methodList = new ArrayList<Method>(); HashMap<ArrayList<Class<?>>, String> apiMap = new HashMap<ArrayList<Class<?>>, String>(); for (Class<?> decoratorClass : _factory.getDecoratorClasses()) { for (Method method : decoratorClass.getMethods()) { if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers()) || Modifier.isPrivate(method.getModifiers()) || (method.getDeclaringClass() == Object.class)) { //|| (method.getDeclaringClass() == Object.class // && ! method.getName().equals("toString"))) { continue; } if (! containsMethod(methodList, method)) { methodList.add(method); } } } for (Method method : methodList) { generateDecoratorMethodDecl(out, method); } out.println(); out.println("public static void __caucho_init_decorators(java.util.List<javax.enterprise.inject.spi.Decorator<?>> decoratorList)"); out.println("{"); out.pushDepth(); for (Method method : methodList) { out.print("_caucho_decorator_" + method.getName() + "_m"); out.print(" = com.caucho.config.gen.CandiUtil.createDecoratorMethods(decoratorList, "); out.print("\"" + method.getName() + "\""); for (int i = 0; i < method.getParameterTypes().length; i++) { out.print(", "); out.printClass(method.getParameterTypes()[i]); out.print(".class"); } out.println(");"); } if (isPassivating()) { String beanClassName = getFactory().getAspectBeanFactory().getInstanceClassName(); out.println(); out.print("com.caucho.config.gen.CandiUtil.validatePassivatingDecorators("); out.print(beanClassName + ".class, "); out.println("decoratorList);"); } out.popDepth(); out.println("}"); out.println(); out.print("static class "); out.print(className); out.print(" "); for (Class<?> cl : _factory.getDecoratorClasses()) { if (! cl.isInterface()) { out.print(" extends "); out.printClass(cl); } } boolean isFirst = true; for (Class<?> cl : _factory.getDecoratorClasses()) { if (! cl.isInterface()) continue; if (isFirst) out.print(" implements "); else out.print(", "); isFirst = false; out.printClass(cl); } out.println(" {"); out.pushDepth(); // String beanClassName = getBeanType().getJavaClass().getName(); String beanClassName = _factory.getInstanceClassName(); out.println("private int _index;"); out.println("private " + beanClassName + " _bean;"); out.println("private Object [] _delegates;"); out.println(); out.print(className + "(int index, " + beanClassName + " bean, Object []delegates)"); out.println("{"); out.println(" _index = index;"); out.println(" _bean = bean;"); out.println(" _delegates = delegates;"); out.println("}"); out.println(); out.println("final " + beanClassName + " __caucho_getBean()"); out.println("{"); /* out.println(" return " + getBusinessMethod().getView().getViewClassName() + ".this;"); */ out.println(" return _bean;"); out.println("}"); for (Method method : methodList) { generateDecoratorMethod(out, method, apiMap); } out.popDepth(); out.println("}"); for (Map.Entry<ArrayList<Class<?>>, String> entry : apiMap.entrySet()) { ArrayList<Class<?>> apis = entry.getKey(); String name = entry.getValue(); out.println(); out.println("static final Class []" + name + " = new Class[] {"); out.pushDepth(); for (int i = 0; i < apis.size(); i++) { out.printClass(apis.get(i)); out.println(".class,"); } out.popDepth(); out.println("};"); } } private void generateDecoratorMethodDecl(JavaWriter out, Method method) throws IOException { out.println("static java.lang.reflect.Method []_caucho_decorator_" + method.getName() + "_m;"); } private void generateDecoratorMethod(JavaWriter out, Method method, HashMap<ArrayList<Class<?>>, String> apiMap) throws IOException { AnnotatedMethod<? super X> annMethod = AnnotatedTypeUtil.findMethod(getBeanType(), method.getName(), method.getParameterTypes()); String uniqueName = getUniqueName(out); ArrayList<Class<?>> apis = getMethodApis(method); String apiName = apiMap.get(apis); if (apiName == null && apis.size() > 1) { apiName = uniqueName + "_api_" + apiMap.size(); apiMap.put(apis, apiName); } out.println(); out.print("public "); out.printClass(method.getReturnType()); out.print(" "); out.print(method.getName()); out.print("("); Class<?>[] paramTypes = method.getParameterTypes(); for (int i = 0; i < paramTypes.length; i++) { if (i != 0) out.print(", "); out.printClass(paramTypes[i]); out.print(" a" + i); } out.println(")"); Class<?>[] exnTypes = method.getExceptionTypes(); if (exnTypes.length > 0) { out.print(" throws "); for (int i = 0; i < exnTypes.length; i++) { if (i != 0) out.print(", "); out.printClass(exnTypes[i]); } } out.println("{"); out.pushDepth(); if (annMethod != null && annMethod.isAnnotationPresent(Inject.class)) { out.println(_decoratorClass + " var = " + _decoratorLocalVar + ".get();"); printDecoratorSuperCall(out, method, annMethod); } else { out.println(_decoratorClass + " var = " + _decoratorLocalVar + ".get();"); // out.println("Object []delegates = var.__caucho_getBean()." + _decoratorIndexVar + ";"); // out.println("Object []delegates = _bean != null ? _bean." + _decoratorIndexVar + " : null;"); // out.println("Object []delegates = var._bean.__caucho_getDelegates();"); out.println("Object []delegates = var._delegates;"); out.println(); out.print("var._index = com.caucho.config.gen.CandiUtil.nextDelegate("); out.print("delegates, "); /* if (apis.size() > 1) { out.print(apiName); } else { out.printClass(decoratorType); out.print(".class"); } */ out.print("_caucho_decorator_" + method.getName() + "_m"); out.println(", var._index);"); out.println(); out.println("if (var._index >= 0) {"); out.pushDepth(); out.println("Object delegate = delegates[var._index];"); for (int j = 0; j < apis.size(); j++) { if (j > 0) out.print("else "); if (j + 1 < apis.size()) { out.print("if (delegate instanceof "); out.printClass(apis.get(j)); out.print(")"); } if (apis.size() > 1) { out.println(); out.print(" "); } if (! void.class.equals(method.getReturnType())) { out.print("return ("); out.printClass(method.getReturnType()); out.print(") "); } /* out.print("(("); out.printClass(apis.get(j)); out.print(") delegate)." + method.getName()); */ out.print("com.caucho.config.gen.CandiUtil.invoke("); out.print("_caucho_decorator_" + method.getName() + "_m["); out.print("var._index"); out.print("], delegate"); for (int i = 0; i < paramTypes.length; i++) { out.print(", "); out.print("a" + i); } out.println(");"); } out.popDepth(); out.println("}"); out.println("else"); out.pushDepth(); printDecoratorSuperCall(out, method, annMethod); } out.popDepth(); out.println("}"); } private void printDecoratorSuperCall(JavaWriter out, Method method, AnnotatedMethod<? super X> annMethod) throws IOException { Class<?>[] paramTypes = method.getParameterTypes(); if (! void.class.equals(method.getReturnType())) out.print("return "); if (isProxy() || annMethod != null && annMethod.isAnnotationPresent(Inject.class)) { out.print("var.__caucho_getBean()."); out.print(method.getName()); } else { out.print("var.__caucho_getBean()."); String declName = annMethod.getDeclaringType().getJavaClass().getSimpleName(); out.print("__caucho_" + declName + "_" + method.getName() + "_" + _interceptionType); } out.print("("); for (int i = 0; i < paramTypes.length; i++) { if (i != 0) out.print(", "); out.print("a" + i); } out.println(");"); out.popDepth(); } // // method generators // private void generateDecoratorMethod(JavaWriter out) throws IOException { Method javaMethod = getJavaMethod(); out.println(); out.print("private "); out.printClass(javaMethod.getReturnType()); out.print(" __caucho_"); out.print(javaMethod.getName()); out.print("_decorator("); Class<?>[] types = javaMethod.getParameterTypes(); for (int i = 0; i < types.length; i++) { Class<?> type = types[i]; if (i != 0) out.print(", "); out.printClass(type); out.print(" a" + i); } out.println(")"); AspectGeneratorUtil.generateThrows(out, javaMethod.getExceptionTypes()); out.println("{"); out.pushDepth(); if (! void.class.equals(javaMethod.getReturnType())) { out.printClass(javaMethod.getReturnType()); out.println(" result;"); } generateDecoratorCall(out); if (! void.class.equals(javaMethod.getReturnType())) { out.println("return result;"); } out.popDepth(); out.println("}"); } private void generateDecoratorPreTry(JavaWriter out) throws IOException { out.print(_decoratorClass + " oldDecorator = "); out.println(_decoratorLocalVar + ".get();"); } private void generateDecoratorPreCall(JavaWriter out) throws IOException { String decoratorSetName = _decoratorSetName; assert(decoratorSetName != null); out.println("Object []caucho_delegates = " + getBeanFactory().getBeanInfo() + ".__caucho_getDelegates();"); out.println(); out.print(_decoratorClass + " delegate = "); out.print("new " + _decoratorClass + "("); out.print("caucho_delegates.length, "); out.print(_factory.getAspectBeanFactory().getBeanInstance() + ", "); out.print("caucho_delegates"); out.println(");"); out.print(_decoratorLocalVar); out.println(".set(delegate);"); } /** * Generates the low-level decorator call at the end of the chain. */ private void generateDecoratorCall(JavaWriter out) throws IOException { String decoratorSetName = _decoratorSetName; assert(decoratorSetName != null); Method javaMethod = getJavaMethod(); //_bizMethod.generateTailCall(out); if (! void.class.equals(javaMethod.getReturnType())) out.print("result = "); out.print("__caucho_delegate."); out.print(javaMethod.getName()); out.print("("); for (int i = 0; i < javaMethod.getParameterTypes().length; i++) { if (i != 0) out.print(", "); out.print("a" + i); } out.println(");"); } private void generateDecoratorFinally(JavaWriter out) throws IOException { out.print(_decoratorLocalVar); out.println(".set(oldDecorator);"); } // // utilities // private String getUniqueName(JavaWriter out) { if (_uniqueName == null) { String name = getJavaMethod().getName(); _uniqueName = ("_" + name + "_" + _interceptionType + "_" + out.generateId()); } return _uniqueName; } private String getDecoratorSetName(JavaWriter out, Map<String,Object> map) { if (_decoratorSetName != null) return _decoratorSetName; HashMap<HashSet<Class<?>>,String> nameMap; nameMap = (HashMap<HashSet<Class<?>>,String>) map.get("decorator_name_map"); if (nameMap == null) { nameMap = new HashMap<HashSet<Class<?>>,String>(); map.put("decorator_name_map", nameMap); } String name = nameMap.get(_decoratorSet); if (name == null) { name = "__caucho_decorator_" + out.generateId(); nameMap.put(_decoratorSet, name); } _decoratorSetName = name; return name; } private void generateAnnotation(JavaWriter out, Annotation ann) throws IOException { out.print("new javax.enterprise.util.AnnotationLiteral<"); out.printClass(ann.annotationType()); out.print(">() {"); boolean isFirst = true; for (Method method : ann.annotationType().getMethods()) { if (method.getDeclaringClass().equals(Object.class)) continue; if (method.getDeclaringClass().equals(Annotation.class)) continue; if (method.getName().equals("annotationType")) continue; if (method.getParameterTypes().length > 0) continue; if (void.class.equals(method.getReturnType())) continue; if (method.isAnnotationPresent(Nonbinding.class)) continue; out.pushDepth(); /* if (! isFirst) out.print(","); */ isFirst = false; out.println(); out.print("public "); out.printClass(method.getReturnType()); out.print(" " + method.getName() + "() { return "); Object value = null; try { method.setAccessible(true); value = method.invoke(ann); } catch (Exception e) { throw ConfigException.create(e); } printValue(out, value); out.println("; }"); out.popDepth(); } out.print("}"); } private void printValue(JavaWriter out, Object value) throws IOException { if (value == null) out.print("null"); else if (value instanceof String) { out.print("\""); out.printJavaString((String) value); out.print("\""); } else if (value instanceof Character) { out.print("\'"); out.printJavaString(String.valueOf(value)); out.print("\'"); } else if (value instanceof Enum<?>) { out.printClass(value.getClass()); out.print("." + value); } else if (value instanceof Class<?>) { out.printClass((Class<?>) value); out.print(".class"); } else out.print(value); } private ArrayList<Class<?>> getMethodApis(Method method) { ArrayList<Class<?>> apis = new ArrayList<Class<?>>(); for (Class<?> decoratorClass : _factory.getDecoratorClasses()) { if (containsMethod(decoratorClass.getMethods(), method) && ! apis.contains(decoratorClass)) apis.add(decoratorClass); } return apis; } private boolean hasInterceptor() { return (_interceptors != null && _interceptors.size() > 0 || _interceptorBinding != null && _interceptorBinding.size() > 0 || getAroundInvokeMethod() != null || _factory.isSelfInterceptor() || _isEpilogue); } private boolean hasDecorator() { return _decoratorSet != null; } private void generateTail(JavaWriter out) throws IOException { Method javaMethod = getJavaMethod(); out.println(); out.print("private "); out.printClass(javaMethod.getReturnType()); out.print(" __caucho_"); out.print(javaMethod.getDeclaringClass().getSimpleName()); out.print("_" + javaMethod.getName()); out.print("_" + _interceptionType); out.print("("); Class<?>[] types = javaMethod.getParameterTypes(); for (int i = 0; i < types.length; i++) { Class<?> type = types[i]; if (i != 0) out.print(", "); out.printClass(type); out.print(" a" + i); } out.println(")"); AspectGeneratorUtil.generateThrows(out, javaMethod.getExceptionTypes()); out.println(); out.println("{"); out.pushDepth(); if (! void.class.equals(javaMethod.getReturnType())) { out.printClass(javaMethod.getReturnType()); out.println(" result;"); } generateTailCall(out, getFactory().getAspectBeanFactory().getBeanSuper()); if (! void.class.equals(javaMethod.getReturnType())) out.println("return result;"); out.popDepth(); out.println("}"); } private void generateNullTail(JavaWriter out) throws IOException { out.println(); out.println("private void __caucho_nullPostConstruct()"); out.println("{"); out.pushDepth(); out.popDepth(); out.println("}"); out.println(); out.println("private void __caucho_nullPreDestroy()"); out.println("{"); out.pushDepth(); out.popDepth(); out.println("}"); } /** * Generates the call to the implementation bean. * * @param superVar java code to reference the implementation */ public void generateTailCall(JavaWriter out, String superVar) throws IOException { super.generateCall(out); /* Method javaMethod = getJavaMethod(); if (Modifier.isStatic(javaMethod.getModifiers())) superVar = javaMethod.getDeclaringClass().getName(); out.println(); if (! void.class.equals(javaMethod.getReturnType())) { out.print("result = "); } out.print(superVar + "." + javaMethod.getName() + "("); Class<?>[] types = javaMethod.getParameterTypes(); for (int i = 0; i < types.length; i++) { if (i != 0) out.print(", "); out.print(" a" + i); } out.println(");"); */ /* // ejb/12b0 if (! "super".equals(superVar)) generatePostCall(out); */ } private boolean containsMethod(ArrayList<Method> methodList, Method method) { for (Method oldMethod : methodList) { if (isMatch(oldMethod, method)) return true; } return false; } private void addInterceptorBindings(HashMap<Class<?>,Annotation> interceptorTypes, Annotation ann) { Class<?> annType = ann.annotationType(); if (annType.isAnnotationPresent(InterceptorBinding.class)) { interceptorTypes.put(ann.annotationType(), ann); } if (annType.isAnnotationPresent(Stereotype.class)) { for (Annotation subAnn : annType.getAnnotations()) { addInterceptorBindings(interceptorTypes, subAnn); } } } private boolean containsMethod(Method[] methodList, Method method) { for (Method oldMethod : methodList) { if (isMatch(oldMethod, method)) return true; } return false; } private boolean isMostGeneralException(Class<?>[] exnList, Class<?> cl) { for (Class<?> exn : exnList) { if (exn != cl && exn.isAssignableFrom(cl)) return false; } return true; } private Method findInterceptorMethod(Class<?> cl) { if (cl == null) return null; for (Method method : cl.getDeclaredMethods()) { if (method.isAnnotationPresent(AroundInvoke.class)) return method; } return findInterceptorMethod(cl.getSuperclass()); } private boolean isMatch(Method methodA, Method methodB) { if (! methodA.getName().equals(methodB.getName())) return false; Class<?>[] paramA = methodA.getParameterTypes(); Class<?>[] paramB = methodB.getParameterTypes(); if (paramA.length != paramB.length) return false; for (int i = 0; i < paramA.length; i++) { if (! paramA[i].equals(paramB[i])) return false; } return true; } private void generateGetMethod(JavaWriter out, String className, String methodName, Class<?>[] paramTypes) throws IOException { if (false && _interceptionType == InterceptionType.POST_CONSTRUCT) { out.printClass(CandiUtil.class); out.print(".findAccessible("); out.print(_factory.getGeneratedClassName()); out.print(".class, \"__caucho_postConstruct_" + methodName + "\");"); } else { out.printClass(CandiUtil.class); out.print(".findAccessibleMethod("); out.print(className); out.print(".class, \"" + methodName + "\""); for (Class<?> type : paramTypes) { out.print(", "); out.printClass(type); out.print(".class"); } out.print(")"); } } protected void printCastClass(JavaWriter out, Type type) throws IOException { if (boolean.class.equals(type)) out.print("Boolean"); else if (char.class.equals(type)) out.print("Character"); else if (byte.class.equals(type)) out.print("Byte"); else if (short.class.equals(type)) out.print("Short"); else if (int.class.equals(type)) out.print("Integer"); else if (long.class.equals(type)) out.print("Long"); else if (float.class.equals(type)) out.print("Float"); else if (double.class.equals(type)) out.print("Double"); else out.printType(type); } public static void nullMethod() { } static class InterceptionBinding { private final InterceptionType _type; private final ArrayList<Annotation> _binding; private final ArrayList<Class<?>> _interceptors; public InterceptionBinding(InterceptionType type, ArrayList<Annotation> binding, ArrayList<Class<?>> interceptors) { _type = type; _binding = binding; _interceptors = interceptors; } @Override public int hashCode() { int hashCode = _type.hashCode() * 65521; if (_binding != null) hashCode += _binding.hashCode(); if (_interceptors != null) hashCode += _interceptors.hashCode(); return hashCode; } @Override public boolean equals(Object o) { if (o == this) return true; else if (! (o instanceof InterceptionBinding)) return false; InterceptionBinding binding = (InterceptionBinding) o; if (! _type.equals(binding._type)) return false; if (_binding == binding._binding) { } else if (_binding == null || ! _binding.equals(binding._binding)) return false; if (_interceptors == binding._interceptors) { } else if (_interceptors == null || ! _interceptors.equals(binding._interceptors)) return false; return true; } } static { Method nullMethod = null; try { nullMethod = InterceptorGenerator.class.getMethod("nullMethod"); } catch (Exception e) { e.printStackTrace(); log.log(Level.WARNING, e.toString(), e); } _nullMethod = nullMethod; } }