/* * 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.ejb.gen; import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; import javax.annotation.PostConstruct; import javax.ejb.TransactionAttribute; import static javax.ejb.TransactionAttributeType.REQUIRED; import javax.enterprise.inject.spi.AnnotatedMethod; import javax.enterprise.inject.spi.AnnotatedType; import com.caucho.config.gen.AspectBeanFactory; import com.caucho.config.gen.AspectGenerator; import com.caucho.config.gen.BeanGenerator; import com.caucho.config.gen.LifecycleAspectBeanFactory; import com.caucho.config.inject.InjectManager; import com.caucho.config.reflect.AnnotatedTypeUtil; import com.caucho.inject.Module; import com.caucho.java.JavaWriter; /** * Generates the skeleton for a message bean. */ @Module public class MessageGenerator<X> extends BeanGenerator<X> { private AspectBeanFactory<X> _aspectBeanFactory; private ArrayList<AspectGenerator<X>> _businessMethods = new ArrayList<AspectGenerator<X>>(); private ArrayList<AnnotatedMethod<? super X>> _annotatedMethods = new ArrayList<AnnotatedMethod<? super X>>(); private final AspectBeanFactory<X> _lifecycleAspectFactory; public MessageGenerator(String ejbName, AnnotatedType<X> ejbClass) { super(toFullClassName(ejbName, ejbClass.getJavaClass().getName()), ejbClass); InjectManager manager = InjectManager.create(); _aspectBeanFactory = new MessageAspectBeanFactory<X>(manager, getBeanType()); _lifecycleAspectFactory = new LifecycleAspectBeanFactory<X>(_aspectBeanFactory, manager, getBeanType()); } protected AspectBeanFactory<X> getLifecycleAspectFactory() { return _lifecycleAspectFactory; } private static String toFullClassName(String ejbName, String className) { StringBuilder sb = new StringBuilder(); /* sb.append("_ejb."); if (! Character.isJavaIdentifierStart(ejbName.charAt(0))) sb.append('_'); for (int i = 0; i < ejbName.length(); i++) { char ch = ejbName.charAt(i); if (ch == '/') sb.append('.'); else if (Character.isJavaIdentifierPart(ch)) sb.append(ch); else sb.append('_'); } sb.append("."); sb.append(className); */ sb.append(className); sb.append("__MessageProxy"); return sb.toString(); } public String getContextClassName() { return getClassName(); } @Override public String getViewClassName() { return getClassName(); } @Override protected AspectBeanFactory<X> getAspectBeanFactory() { return _aspectBeanFactory; } /** * Returns the introspected methods */ @Override public ArrayList<AspectGenerator<X>> getMethods() { return _businessMethods; } /** * Introspects the bean. */ @Override public void introspect() { super.introspect(); introspectType(getBeanType()); introspectImpl(); } private void introspectType(AnnotatedType<? super X> type) { for (AnnotatedMethod<? super X> method : type.getMethods()) introspectMethod(method); } private void introspectMethod(AnnotatedMethod<? super X> method) { _annotatedMethods.add(method); } /** * Introspects the APIs methods, producing a business method for * each. */ private void introspectImpl() { for (AnnotatedMethod<? super X> method : _annotatedMethods) { introspectMethodImpl(method); } } private void introspectMethodImpl(AnnotatedMethod<? super X> apiMethod) { Method javaMethod = apiMethod.getJavaMember(); if (javaMethod.getDeclaringClass().equals(Object.class)) return; if (javaMethod.getDeclaringClass().getName().startsWith("javax.ejb.")) return; /* if (javaMethod.getName().startsWith("ejb")) { throw new ConfigException(L.l("{0}: '{1}' must not start with 'ejb'. The EJB spec reserves all methods starting with ejb.", javaMethod.getDeclaringClass(), javaMethod.getName())); } */ int modifiers = javaMethod.getModifiers(); if (! Modifier.isPublic(modifiers)) { return; } if (Modifier.isFinal(modifiers) || Modifier.isStatic(modifiers)) return; if (apiMethod.isAnnotationPresent(PostConstruct.class)) addLifecycleMethod(apiMethod); else addBusinessMethod(apiMethod); } public void addBusinessMethod(AnnotatedMethod<? super X> method) { AspectGenerator<X> bizMethod = _aspectBeanFactory.create(method); if (bizMethod != null) { _businessMethods.add(bizMethod); } } protected void addLifecycleMethod(AnnotatedMethod<? super X> method) { if (getLifecycleAspectFactory() == null) return; AspectGenerator<X> initMethod = getLifecycleAspectFactory().create(method); if (initMethod != null && ! _businessMethods.contains(initMethod)) { _businessMethods.add(initMethod); } } /** * Generates the message session bean */ @Override public void generate(JavaWriter out) throws IOException { generateTopComment(out); out.println(); out.println("package " + getPackageName() + ";"); out.println(); out.println("import com.caucho.config.*;"); out.println("import com.caucho.ejb.*;"); out.println("import com.caucho.ejb.message.*;"); out.println(); out.println("import java.util.*;"); out.println("import java.lang.reflect.*;"); out.println("import javax.ejb.*;"); out.println("import javax.transaction.*;"); out.println("import javax.transaction.xa.*;"); out.println("import javax.resource.spi.endpoint.*;"); out.println(); out.println("public class " + getClassName() + " extends " + getBeanType().getJavaClass().getName() + " implements MessageEndpoint, CauchoMessageEndpoint"); out.println("{"); out.pushDepth(); /* // ejb/0931 out.println(); out.println("private static final com.caucho.ejb3.xa.XAManager _xa"); out.println(" = new com.caucho.ejb3.xa.XAManager();"); */ out.println("private static HashSet<Method> _xaMethods = new HashSet<Method>();"); out.println(); out.println("private MessageManager _server;"); out.println("private XAResource _xaResource;"); out.println("private boolean _isXa;"); HashMap<String,Object> map = new HashMap<String,Object>(); map.put("caucho.ejb.xa", "true"); // view.generateContextPrologue(out); generateBeanPrologue(out, map); out.println(); //out.println("public " + getClassName() + "(MessageManager server)"); out.println("public " + getClassName() + "()"); out.println("{"); out.pushDepth(); // out.println("_server = server;"); /* if (MessageDrivenBean.class.isAssignableFrom(getBeanType().getJavaClass())) { out.println("setMessageDrivenContext(server.getMessageContext());"); } */ generateBeanConstructor(out); out.popDepth(); out.println("}"); out.println(); out.println("static {"); out.pushDepth(); out.println("try {"); out.pushDepth(); // XXX: 4.0.7 for (AspectGenerator<X> bizMethod : getMethods()) { AnnotatedMethod<?> method = bizMethod.getMethod(); TransactionAttribute xa; xa = method.getAnnotation(TransactionAttribute.class); if (xa == null) xa = method.getDeclaringType().getAnnotation(TransactionAttribute.class); if (xa != null && REQUIRED.equals(xa.value())) { addXaMethods(out, method.getJavaMember()); } } out.popDepth(); out.println("} catch (Exception e) {"); out.println(" throw new RuntimeException(e);"); out.println("}"); out.popDepth(); out.println("}"); out.println(); out.println("public void __caucho_setXAResource(XAResource xaResource)"); out.println("{"); out.println(" _xaResource = xaResource;"); out.println("}"); out.println(); out.println("public void beforeDelivery(java.lang.reflect.Method method)"); out.println("{"); out.println(" if (_xaMethods.contains(method)) {"); out.println(" _isXa = (_xa.beginRequired() == null);"); out.println(); out.println(" if (_isXa && _xaResource != null)"); out.println(" _xa.enlist(_xaResource);"); out.println(" }"); out.println("}"); out.println("public void afterDelivery()"); out.println("{"); out.println(" if (_isXa) {"); out.println(" _isXa = false;"); out.println(" _xa.commit();"); out.println(" }"); out.println("}"); out.println(); out.println("public void release()"); out.println("{"); out.pushDepth(); if (getImplMethod("ejbRemove", new Class[0]) != null) { out.println("ejbRemove();"); } out.popDepth(); out.println("}"); /* for (View view : getViews()) { view.generateContextPrologue(out); } */ generateView(out); generateDependency(out); out.popDepth(); out.println("}"); } private void addXaMethods(JavaWriter out, Method method) throws IOException { printXaMethod(out, method); for (Class<?> api : method.getDeclaringClass().getInterfaces()) { Method subMethod = AnnotatedTypeUtil.findMethod(api.getMethods(), method); if (subMethod != null) printXaMethod(out, subMethod); } } private void printXaMethod(JavaWriter out, Method api) throws IOException { out.print("_xaMethods.add("); out.printClass(api.getDeclaringClass()); out.print(".class.getMethod(\""); out.print(api.getName()); out.print("\", new Class[] { "); for (Class<?> cl : api.getParameterTypes()) { out.printClass(cl); out.print(".class, "); } out.println("}));"); } /** * Generates the view code. */ private void generateView(JavaWriter out) throws IOException { HashMap<String,Object> map = new HashMap<String,Object>(); map.put("caucho.ejb.xa", "done"); out.println(); out.println("private static final com.caucho.ejb.util.XAManager _xa"); out.println(" = new com.caucho.ejb.util.XAManager();"); /* ejb/0fbm for (BusinessMethodGenerator bizMethod : _businessMethods) { bizMethod.generatePrologueTop(out, map); } */ for (AspectGenerator<X> bizMethod : _businessMethods) { bizMethod.generate(out, map); } generatePostConstruct(out, map); } private AnnotatedMethod<? super X> getImplMethod(String name, Class<?> []param) { return AnnotatedTypeUtil.findMethod(getBeanType(), name, param); } }