com.caucho.config.gen.BeanGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of resin-kernel Show documentation
Show all versions of resin-kernel Show documentation
Kernel for Resin Java Application Server
The newest version!
/*
* Copyright (c) 1998-2012 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.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.interceptor.InterceptorBinding;
import javax.interceptor.Interceptors;
import com.caucho.config.reflect.AnnotatedMethodImpl;
import com.caucho.inject.Module;
import com.caucho.java.JavaWriter;
import com.caucho.java.gen.DependencyComponent;
import com.caucho.java.gen.GenClass;
import com.caucho.make.ClassDependency;
import com.caucho.make.VersionDependency;
import com.caucho.vfs.PersistentDependency;
/**
* Generates the skeleton for a bean.
*/
@Module
abstract public class BeanGenerator extends GenClass
{
private final AnnotatedType _beanType;
private DependencyComponent _dependency = new DependencyComponent();
protected BeanGenerator(String fullClassName,
AnnotatedType beanType)
{
super(fullClassName);
_beanType = beanType;
addDependency(new VersionDependency());
addDependency(beanType.getJavaClass());
}
public AnnotatedType getBeanType()
{
return _beanType;
}
protected void addDependency(PersistentDependency depend)
{
_dependency.addDependency(depend);
}
protected void addDependency(Class> cl)
{
_dependency.addDependency(new ClassDependency(cl));
}
public String getBeanClassName()
{
return getBeanType().getJavaClass().getName();
}
public String getViewClassName()
{
throw new UnsupportedOperationException(getClass().getName());
}
public boolean isRemote()
{
return false;
}
public boolean isProxy()
{
return false;
}
/**
* Returns the introspected methods
*/
public ArrayList> getMethods()
{
throw new UnsupportedOperationException(getClass().getName());
}
protected abstract AspectBeanFactory getAspectBeanFactory();
protected AspectBeanFactory getLifecycleAspectFactory()
{
return getAspectBeanFactory();
}
public void introspect()
{
}
//
// Java generation
//
public void generateClassStaticFields(JavaWriter out)
throws IOException
{
out.println("private static final java.util.logging.Logger __caucho_log");
out.println(" = java.util.logging.Logger.getLogger(\"" + getFullClassName() + "\");");
out.println("private static RuntimeException __caucho_exception;");
out.println();
out.println("public static RuntimeException __caucho_getException()");
out.println("{");
out.println(" return __caucho_exception;");
out.println("}");
}
/**
* Generates the view contents
*/
/*
@Override
abstract public void generate(JavaWriter out)
throws IOException;
*/
/**
* Generates the view contents
*/
public void generateDestroyViews(JavaWriter out)
throws IOException
{
// view.generateDestroy(out);
}
/**
* Generates context object's constructor
*/
public void generateContextObjectConstructor(JavaWriter out)
throws IOException
{
}
/**
* Generates timer code
*/
public void generateTimer(JavaWriter out)
throws IOException
{
}
/**
* Frees a bean instance.
*/
public void generateFreeInstance(JavaWriter out, String name)
throws IOException
{
throw new UnsupportedOperationException(getClass().getName());
}
/**
* Generates any global destroy
*/
public void generateDestroy(JavaWriter out, HashMap map)
throws IOException
{
generatePreDestroy(out, map);
out.println();
out.println("public void __caucho_destroy(com.caucho.config.inject.CreationalContextImpl env)");
out.println("{");
out.pushDepth();
out.println("__caucho_preDestroy();");
generateDestroyImpl(out);
out.popDepth();
out.println("}");
}
protected void generateDestroyImpl(JavaWriter out)
throws IOException
{
HashMap map = new HashMap();
for (AspectGenerator method : getMethods()) {
method.generateDestroy(out, map);
}
}
/**
* Generates constructor additions
*/
public void generateProxyConstructor(JavaWriter out)
throws IOException
{
HashMap map = new HashMap();
generateProxyConstructor(out, map);
}
/**
* Generates constructor additions
*/
public void generateProxyConstructor(JavaWriter out,
HashMap map)
throws IOException
{
for (AspectGenerator method : getMethods()) {
method.generateProxyConstructor(out, map);
}
}
/**
* Generates constructor additions
*/
public void generateBeanConstructor(JavaWriter out)
throws IOException
{
HashMap map = new HashMap();
generateBeanConstructor(out, map);
}
/**
* Generates constructor additions
*/
public void generateBeanConstructor(JavaWriter out,
HashMap map)
throws IOException
{
for (AspectGenerator method : getMethods()) {
method.generateBeanConstructor(out, map);
}
}
/**
* Generates prologue additions
*/
public void generateBeanPrologue(JavaWriter out,
HashMap map)
throws IOException
{
for (AspectGenerator method : getMethods()) {
method.generateBeanPrologue(out, map);
}
}
protected void generateInject(JavaWriter out,
HashMap map)
throws IOException
{
out.println();
out.println("public Object []__caucho_inject(Object []delegates"
+ ", Object []interceptors"
+ ", com.caucho.config.inject.CreationalContextImpl> parentEnv)");
out.println("{");
out.pushDepth();
generateInjectContent(out, map);
out.println("return interceptors;");
out.popDepth();
out.println("}");
}
protected void generateInjectContent(JavaWriter out,
HashMap map)
throws IOException
{
for (AspectGenerator method : getMethods()) {
method.generateInject(out, map);
}
getAspectBeanFactory().generateInject(out, map);
}
protected void generateDelegate(JavaWriter out,
HashMap map)
throws IOException
{
out.println();
out.println("public Object __caucho_getDelegate()");
out.println("{");
out.print(" return ");
out.print(getAspectBeanFactory().getBeanInstance());
out.println(";");
out.println("}");
}
protected void generatePostConstruct(JavaWriter out,
HashMap map)
throws IOException
{
generatePostConstructImpl(out, map);
}
protected void generatePostConstructImpl(JavaWriter out,
HashMap map)
throws IOException
{
ArrayList postConstructMethods
= getLifecycleAspects(PostConstruct.class);
if (postConstructMethods.size() == 0
&& getBeanType().isAnnotationPresent(Interceptors.class)) {
generateDummyPostConstruct(postConstructMethods, out, map);
}
// postConstructMethods = getLifecycleAspects(PostConstruct.class);
out.println();
out.println("public void __caucho_postConstruct()");
out.println(" throws Exception");
out.println("{");
out.pushDepth();
// postConstructMethods = getLifecycleMethods(PostConstruct.class);
/*
for (AspectGenerator> method : getLifecycleAspects(PostConstruct.class)) {
// method.generatePostConstruct(out, map);
}
*/
Method postConstructMethod = null;
int methodsSize = postConstructMethods.size();
for (int i = 0; i < methodsSize && postConstructMethod == null; i++) {
Method method = postConstructMethods.get(i);
if (Modifier.isPrivate(method.getModifiers())
&& i + 1 < methodsSize) {
// ejb/1064, ejb/1063
continue;
}
postConstructMethod = method;
}
// ejb/1060 - TCK
boolean isLifecycle = false;
for (int i = 0; i < methodsSize; i++) {
Method method = postConstructMethods.get(i);
if (postConstructMethod != method) {
generateLifecycleMethod(out, i, method, "postConstruct");
}
else if (! isLifecycle) {
isLifecycle = true;
String declName = method.getDeclaringClass().getSimpleName();
String methodName = method.getName();
out.println("__caucho_lifecycle_" + declName + "_" + methodName + "();");
}
}
/*
// ejb/4018, ejb/1060 - TCK
for (int i = 0; i < methodsSize; i++) {
Method method = postConstructMethods.get(i);
String declName = method.getDeclaringClass().getSimpleName();
String methodName = method.getName();
out.println("__caucho_lifecycle_" + declName + "_" + methodName + "();");
}
*/
// getAspectBeanFactory().generatePostConstruct(out, map);
out.popDepth();
out.println("}");
generateLifecycleMethodReflection(out, postConstructMethods, "postConstruct");
out.println();
out.println("private void __caucho_postConstructImpl()");
out.println("{");
out.pushDepth();
generateLifecycleMethods(out, postConstructMethods, "postConstruct");
out.popDepth();
out.println("}");
}
private void generateDummyPostConstruct(ArrayList postConstructMethods,
JavaWriter out,
HashMap map)
throws IOException
{
if (postConstructMethods.size() > 0)
throw new IllegalStateException();
Method method = CandiUtil.getDummyPostConstruct();
AnnotatedMethodImpl annMethod;
annMethod = new AnnotatedMethodImpl(getBeanType(), null, method);
annMethod.addAnnotation(new PostConstructLiteral());
AspectGenerator methodGen
= getLifecycleAspectFactory().create(annMethod);
if (methodGen != null) {
methodGen.generate(out, map);
out.println("public static void __caucho_CandiUtil_dummyPostConstruct_POST_CONSTRUCT() {}");
postConstructMethods.add(method);
}
}
private void generatePreDestroy(JavaWriter out,
HashMap map)
throws IOException
{
ArrayList preDestroyMethods = getLifecycleAspects(PreDestroy.class);
if (preDestroyMethods.size() == 0
&& isInterceptorPresent(getBeanType())) {
generateDummyPreDestroy(preDestroyMethods, out, map);
}
out.println();
out.println("public void __caucho_preDestroy()");
out.println("{");
out.pushDepth();
for (Method method : preDestroyMethods) {
String declName = method.getDeclaringClass().getSimpleName();
String methodName = method.getName();
out.println("__caucho_lifecycle_" + declName + "_" + methodName + "();");
}
// getAspectBeanFactory().generatePostConstruct(out, map);
/*
for (AspectGenerator method : getMethods()) {
method.generatePreDestroy(out, map);
}
getAspectBeanFactory().generatePreDestroy(out, map);
*/
out.popDepth();
out.println("}");
generateLifecycleMethodReflection(out, preDestroyMethods, "preDestroy");
out.println();
out.println("private void __caucho_preDestroyImpl()");
out.println(" throws Exception");
out.println("{");
out.pushDepth();
generateLifecycleMethods(out, preDestroyMethods, "preDestroy");
out.popDepth();
out.println("}");
}
private boolean isInterceptorPresent(AnnotatedType> beanType)
{
for (Annotation ann : beanType.getAnnotations()) {
Class> annType = ann.annotationType();
if (Interceptors.class.equals(annType))
return true;
else if (annType.isAnnotationPresent(InterceptorBinding.class))
return true;
}
return false;
}
private void generateDummyPreDestroy(ArrayList preDestroyMethods,
JavaWriter out,
HashMap map)
throws IOException
{
if (preDestroyMethods.size() > 0)
throw new IllegalStateException();
Method method = CandiUtil.getDummyPreDestroy();
AnnotatedMethodImpl annMethod;
annMethod = new AnnotatedMethodImpl(getBeanType(), null, method);
annMethod.addAnnotation(new PreDestroyLiteral());
AspectGenerator methodGen
= getLifecycleAspectFactory().create(annMethod);
if (methodGen != null) {
methodGen.generate(out, map);
out.println("public static void __caucho_CandiUtil_dummyPreDestroy_PRE_DESTROY() {}");
preDestroyMethods.add(method);
}
}
protected void generateLifecycleMethodReflection(JavaWriter out,
ArrayList methods,
String lifecycleType)
throws IOException
{
for (int i = 0; i < methods.size(); i++) {
Method method = methods.get(i);
String methodName = "__caucho_" + lifecycleType + "_" + i;
out.println();
out.println("static final java.lang.reflect.Method " + methodName);
out.print(" = ");
out.printClass(CandiUtil.class);
out.print(".findAccessibleMethod(");
out.printClass(method.getDeclaringClass());
out.print(".class, \"");
out.print(method.getName());
out.println("\");");
}
}
protected void generateLifecycleMethods(JavaWriter out,
ArrayList methods,
String lifecycleType)
throws IOException
{
for (int i = 0; i < methods.size(); i++) {
generateLifecycleMethod(out, i, methods.get(i), lifecycleType);
}
}
protected void generateLifecycleMethod(JavaWriter out,
int i,
Method method,
String lifecycleType)
throws IOException
{
out.println("try {");
out.pushDepth();
out.println("if (" + getLifecycleInstance() + " != null) {");
out.pushDepth();
out.print("__caucho_" + lifecycleType + "_" + i + ".invoke(");
out.print(getLifecycleInstance());
out.println(");");
out.popDepth();
out.println("}");
out.popDepth();
out.println("} catch (RuntimeException ex) {");
out.println(" throw ex;");
out.println("} catch (java.lang.reflect.InvocationTargetException ex) {");
out.println(" if (ex.getCause() instanceof RuntimeException)");
out.println(" throw (RuntimeException) ex.getCause();");
out.println(" else");
out.println(" throw new RuntimeException(ex);");
out.println("} catch (Exception ex) {");
out.println(" throw new RuntimeException(ex);");
out.println("}");
}
protected String getLifecycleInstance()
{
return getAspectBeanFactory().getBeanInstance();
}
protected ArrayList
getLifecycleMethods(Class extends Annotation> annType)
{
ArrayList methods = new ArrayList();
for (AnnotatedMethod super X> method : getBeanType().getMethods()) {
if (! method.isAnnotationPresent(annType))
continue;
if (method.getParameters().size() != 0)
continue;
methods.add(method.getJavaMember());
}
Collections.sort(methods, new PostConstructComparator());
return methods;
}
protected ArrayList
getLifecycleAspects(Class extends Annotation> annType)
{
ArrayList aspects = new ArrayList();
for (AspectGenerator> gen : getMethods()) {
AnnotatedMethod> method = gen.getMethod();
if (! method.isAnnotationPresent(annType))
continue;
if (method.getParameters().size() != 0)
continue;
aspects.add(method.getJavaMember());
}
Collections.sort(aspects, new PostConstructComparator());
return aspects;
}
protected void generateEpilogue(JavaWriter out, HashMap map)
throws IOException
{
getAspectBeanFactory().generateEpilogue(out, map);
}
/**
* Generates view's business methods
*/
public void generateBusinessMethods(JavaWriter out,
HashMap map)
throws IOException
{
for (AspectGenerator method : getMethods()) {
method.generate(out, map);
}
}
protected void generateDependency(JavaWriter out)
throws IOException
{
_dependency.generate(out);
}
@Override
public String toString()
{
return (getClass().getSimpleName()
+ "[" + _beanType.getJavaClass().getSimpleName() + "]");
}
static class PostConstructComparator implements Comparator {
@Override
public int compare(Method a, Method b)
{
Class> classA = a.getDeclaringClass();
Class> classB = b.getDeclaringClass();
if (classA == classB)
return a.getName().compareTo(b.getName());
else if (classA.isAssignableFrom(classB))
return -1;
else if (classB.isAssignableFrom(classA))
return 1;
else
return a.getName().compareTo(b.getName());
}
}
static class PostConstructAspectComparator
implements Comparator> {
@Override
public int compare(AspectGenerator> genA, AspectGenerator> genB)
{
Method a = genA.getMethod().getJavaMember();
Method b = genB.getMethod().getJavaMember();
Class> classA = a.getDeclaringClass();
Class> classB = b.getDeclaringClass();
if (classA == classB)
return a.getName().compareTo(b.getName());
else if (classA.isAssignableFrom(classB))
return -1;
else if (classB.isAssignableFrom(classA))
return 1;
else
return a.getName().compareTo(b.getName());
}
}
}