This brought some ejb tx regressions on geronimo tck. I can't dig into it because of my poor apache svn connection for now.
---------- Forwarded message ---------- From: <[email protected]> Date: Sat, Jun 4, 2011 at 9:45 AM Subject: svn commit: r1131304 - in /openejb/trunk/openejb3/container: openejb-core/src/main/java/org/apache/openejb/ openejb-core/src/main/java/org/apache/openejb/assembler/classic/ openejb-core/src/main/java/org/apache/openejb/core/managed/ openejb-core/src/ma... To: [email protected] Author: dblevins Date: Sat Jun 4 01:45:46 2011 New Revision: 1131304 URL: http://svn.apache.org/viewvc?rev=1131304&view=rev Log: Fixes OPENEJB-1567: Overriding of per-interface transaction attributes only supported for different method signatures Added: openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/InterfaceTransactionTest.java Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/BeanContext.java openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/MethodInfoUtil.java openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/MethodTransactionBuilder.java openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/managed/ManagedContainer.java openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/singleton/SingletonContainer.java openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/TransactionAttributesTest.java openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/Method.java Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/BeanContext.java URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/BeanContext.java?rev=1131304&r1=1131303&r2=1131304&view=diff ============================================================================== --- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/BeanContext.java (original) +++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/BeanContext.java Sat Jun 4 01:45:46 2011 @@ -41,6 +41,7 @@ import javax.ejb.Timer; import javax.naming.Context; import javax.persistence.EntityManagerFactory; +import com.sun.istack.internal.Nullable; import org.apache.openejb.cdi.OWBInjector; import org.apache.openejb.core.ExceptionType; import org.apache.openejb.core.InstanceContext; @@ -58,8 +59,6 @@ import org.apache.openejb.core.transacti import org.apache.openejb.core.transaction.TransactionType; import org.apache.openejb.util.Duration; import org.apache.openejb.util.Index; -import org.apache.openejb.util.LogCategory; -import org.apache.openejb.util.Logger; import org.apache.webbeans.config.WebBeansContext; import org.apache.xbean.recipe.ConstructionException; @@ -126,6 +125,7 @@ public class BeanContext extends Deploym private final Map<Method, TransactionType> methodTransactionType = new HashMap<Method, TransactionType>(); private final Map<Method, Method> methodMap = new HashMap<Method, Method>(); private final Map<Method, MethodContext> methodContextMap = new HashMap<Method, MethodContext>(); + private final Map<String, ViewContext> viewContextMap = new HashMap<String, ViewContext>(); private Index<EntityManagerFactory,Map> extendedEntityManagerFactories; @@ -412,36 +412,57 @@ public class BeanContext extends Deploym } public TransactionType getTransactionType(Method method) { - // Check the cache - TransactionType type = methodTransactionType.get(method); - if (type != null) { - return type; - } + return getTransactionType(method, null); + } + + public TransactionType getTransactionType(Method method, InterfaceType interfaceType) { + + MethodContext methodContext = null; - // Bean managed EJBs always get the BeanManaged policy - if (isBeanManagedTransaction) { - return TransactionType.BeanManaged; + if (interfaceType != null) { + methodContext = getViewMethodContext(method, interfaceType.getSpecName()); } - // Check the matching bean method for the supplied method - Method beanMethod = getMatchingBeanMethod(method); - if (beanMethod != null){ - type = methodTransactionType.get(beanMethod); - if (type != null) { - return type; - } + if (methodContext == null) methodContext = methodContextMap.get(method); + + if (methodContext == null) { + final Method beanMethod = getMatchingBeanMethod(method); + methodContext = getMethodContext(beanMethod); } - // All transaction attributes should have been set during deployment, so log a message - Logger log = Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources"); - log.debug("The following method doesn't have a transaction policy assigned: " + method); - - // default transaction policy is required - type = getTransactionType(); - - // cache this default to avoid extra log messages - methodTransactionType.put(method, type); - return type; + return methodContext.getTransactionType(); + +// +// // Check the cache +// TransactionType type = methodTransactionType.get(method); +// if (type != null) { +// return type; +// } +// +// // Bean managed EJBs always get the BeanManaged policy +// if (isBeanManagedTransaction) { +// return TransactionType.BeanManaged; +// } +// +// // Check the matching bean method for the supplied method +// Method beanMethod = getMatchingBeanMethod(method); +// if (beanMethod != null){ +// type = methodTransactionType.get(beanMethod); +// if (type != null) { +// return type; +// } +// } +// +// // All transaction attributes should have been set during deployment, so log a message +// Logger log = Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources"); +// log.debug("The following method doesn't have a transaction policy assigned: " + method); +// +// // default transaction policy is required +// type = getTransactionType(); +// +// // cache this default to avoid extra log messages +// methodTransactionType.put(method, type); +// return type; } public TransactionType getTransactionType() { @@ -650,24 +671,41 @@ public class BeanContext extends Deploym * TODO: Move to MethodContext */ public void setMethodTransactionAttribute(Method method, TransactionType transactionType) throws OpenEJBException { + setMethodTransactionAttribute(method, transactionType, null); + } - // Only the NOT_SUPPORTED and REQUIRED transaction attributes may be used for message-driven - // bean message listener methods. The use of the other transaction attributes is not meaningful - // for message-driven bean message listener methods because there is no pre-existing client transaction - // context(REQUIRES_NEW, SUPPORTS) and no client to handle exceptions (MANDATORY, NEVER). - if (componentType.isMessageDriven() && !isBeanManagedTransaction) { - if (transactionType != TransactionType.NotSupported && transactionType != TransactionType.Required) { - - if ((method.equals(this.ejbTimeout) || methodContextMap.get(method).isAsynchronous()) && transactionType == TransactionType.RequiresNew) { - // do nothing. This is allowed as the timer callback method for a message driven bean - // can also have a transaction policy of RequiresNew Sec 5.4.12 of Ejb 3.0 Core Spec - } else { - throw new OpenEJBException("The transaction attribute " + transactionType + " is not supported for the method " - + method.getName() + " of the Message Driven Bean " + beanClass.getName()); - } - } + /** + * TODO: Move to MethodContext + */ + public void setMethodTransactionAttribute(Method method, TransactionType transactionType, String view) throws OpenEJBException { + +// method = getMatchingBeanMethod(method); + + if (view == null) { + getMethodContext(method).setTransactionType(transactionType); + } else { + initViewMethodContext(method, view).setTransactionType(transactionType); } - methodTransactionType.put(method, transactionType); + + return; + +// // Only the NOT_SUPPORTED and REQUIRED transaction attributes may be used for message-driven +// // bean message listener methods. The use of the other transaction attributes is not meaningful +// // for message-driven bean message listener methods because there is no pre-existing client transaction +// // context(REQUIRES_NEW, SUPPORTS) and no client to handle exceptions (MANDATORY, NEVER). +// if (componentType.isMessageDriven() && !isBeanManagedTransaction) { +// if (transactionType != TransactionType.NotSupported && transactionType != TransactionType.Required) { +// +// if ((method.equals(this.ejbTimeout) || methodContextMap.get(method).isAsynchronous()) && transactionType == TransactionType.RequiresNew) { +// // do nothing. This is allowed as the timer callback method for a message driven bean +// // can also have a transaction policy of RequiresNew Sec 5.4.12 of Ejb 3.0 Core Spec +// } else { +// throw new OpenEJBException("The transaction attribute " + transactionType + " is not supported for the method " +// + method.getName() + " of the Message Driven Bean " + beanClass.getName()); +// } +// } +// } +// methodTransactionType.put(method, transactionType); } public List<Method> getRemoveMethods() { @@ -1231,4 +1269,38 @@ public class BeanContext extends Deploym } return buffer.toString(); } + + private MethodContext getViewMethodContext(Method method, String view) { + ViewContext viewContext = this.viewContextMap.get(view); + return (viewContext == null) ? null : viewContext.getMethodContext(method); + } + + private MethodContext initViewMethodContext(Method method, String view) { + ViewContext viewContext = this.viewContextMap.get(view); + if (viewContext == null) { + viewContext = new ViewContext(); + viewContextMap.put(view, viewContext); + } + + return viewContext.initMethodContext(method); + } + + public class ViewContext { + + private final Map<Method, MethodContext> methodContextMap = new HashMap<Method, MethodContext>(); + + public MethodContext getMethodContext(Method method) { + return methodContextMap.get(method); + } + + public MethodContext initMethodContext(Method method) { + MethodContext methodContext = methodContextMap.get(method); + if (methodContext != null) return methodContext; + + methodContext = new MethodContext(BeanContext.this, method); + methodContextMap.put(method, methodContext); + + return methodContext; + } + } } Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/MethodInfoUtil.java URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/MethodInfoUtil.java?rev=1131304&r1=1131303&r2=1131304&view=diff ============================================================================== --- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/MethodInfoUtil.java (original) +++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/MethodInfoUtil.java Sat Jun 4 01:45:46 2011 @@ -309,6 +309,105 @@ public class MethodInfoUtil { return attributes; } + public static Map<ViewMethod, MethodAttributeInfo> resolveViewAttributes(List<? extends MethodAttributeInfo> infos, BeanContext beanContext) { + Map<ViewMethod, MethodAttributeInfo> attributes = new LinkedHashMap<ViewMethod, MethodAttributeInfo>(); + + Method[] wildCardView = getWildCardView(beanContext).toArray(new Method[]{}); + + for (MethodAttributeInfo attributeInfo : infos) { + for (MethodInfo methodInfo : attributeInfo.methods) { + + if (methodInfo.ejbName == null || methodInfo.ejbName.equals("*") || methodInfo.ejbName.equals(beanContext.getEjbName())) { + + List<Method> methods = new ArrayList<Method>(); + + if (methodInfo.methodIntf == null) { + methods.addAll(matchingMethods(methodInfo, wildCardView)); + } else if (methodInfo.methodIntf.equals("Home")) { + methods.addAll(matchingMethods(methodInfo, beanContext.getHomeInterface())); + } else if (methodInfo.methodIntf.equals("Remote")) { + if (beanContext.getRemoteInterface() != null) { + methods.addAll(matchingMethods(methodInfo, beanContext.getRemoteInterface())); + } + for (Class intf : beanContext.getBusinessRemoteInterfaces()) { + methods.addAll(matchingMethods(methodInfo, intf)); + } + } else if (methodInfo.methodIntf.equals("LocalHome")) { + methods.addAll(matchingMethods(methodInfo, beanContext.getLocalHomeInterface())); + } else if (methodInfo.methodIntf.equals("Local")) { + if (beanContext.getLocalInterface() != null) { + methods.addAll(matchingMethods(methodInfo, beanContext.getLocalInterface())); + } + for (Class intf : beanContext.getBusinessRemoteInterfaces()) { + methods.addAll(matchingMethods(methodInfo, intf)); + } + } else if (methodInfo.methodIntf.equals("ServiceEndpoint")) { + methods.addAll(matchingMethods(methodInfo, beanContext.getServiceEndpointInterface())); + } + + for (Method method : methods) { + if (containerMethod(method)) { + continue; + } + + final ViewMethod viewMethod = new ViewMethod(methodInfo.methodIntf, method); + attributes.put(viewMethod, attributeInfo); +// List<MethodAttributeInfo> methodAttributeInfos = attributes.get(method); +// if (methodAttributeInfos == null) { +// methodAttributeInfos = new ArrayList<MethodAttributeInfo>(); +// attributes.put(method, methodAttributeInfos); +// } +// methodAttributeInfos.add(attributeInfo); + } + } + } + } + return attributes; + } + + public static class ViewMethod { + private final String view; + private final Method method; + + public ViewMethod(String view, Method method) { + this.view = view; + this.method = method; + } + + public String getView() { + return view; + } + + public Method getMethod() { + return method; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ViewMethod that = (ViewMethod) o; + + if (!method.equals(that.method)) return false; + if (view != null ? !view.equals(that.view) : that.view != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = view != null ? view.hashCode() : 0; + result = 31 * result + method.hashCode(); + return result; + } + + @Override + public String toString() { + return String.format("%s : %s(%s)", view, method.getName(), Join.join(", ", Classes.getSimpleNames(method.getParameterTypes()))); + } + } + private static boolean containerMethod(Method method) { return (method.getDeclaringClass() == EJBObject.class || method.getDeclaringClass() == EJBHome.class || Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/MethodTransactionBuilder.java URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/MethodTransactionBuilder.java?rev=1131304&r1=1131303&r2=1131304&view=diff ============================================================================== --- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/MethodTransactionBuilder.java (original) +++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/MethodTransactionBuilder.java Sat Jun 4 01:45:46 2011 @@ -17,6 +17,7 @@ package org.apache.openejb.assembler.classic; import static org.apache.openejb.assembler.classic.MethodInfoUtil.resolveAttributes; +import static org.apache.openejb.assembler.classic.MethodInfoUtil.resolveViewAttributes; import org.apache.openejb.BeanContext; import org.apache.openejb.core.transaction.TransactionType; @@ -50,25 +51,35 @@ public class MethodTransactionBuilder { methodTransactionInfos = normalize(methodTransactionInfos); - Map<Method, MethodAttributeInfo> attributes = resolveAttributes(methodTransactionInfos, beanContext); + final Map<MethodInfoUtil.ViewMethod, MethodAttributeInfo> attributes = resolveViewAttributes(methodTransactionInfos, beanContext); Logger log = Logger.getInstance(LogCategory.OPENEJB_STARTUP.createChild("attributes"), MethodTransactionBuilder.class); - if (log.isDebugEnabled()) { - for (Map.Entry<Method, MethodAttributeInfo> entry : attributes.entrySet()) { - Method method = entry.getKey(); - MethodTransactionInfo value = (MethodTransactionInfo) entry.getValue(); - log.debug("Transaction Attribute: " + method + " -- " + MethodInfoUtil.toString(value)); - } - } + final boolean debug = log.isDebugEnabled(); + + for (Map.Entry<MethodInfoUtil.ViewMethod, MethodAttributeInfo> entry : attributes.entrySet()) { + final MethodInfoUtil.ViewMethod viewMethod = entry.getKey(); + final Method method = viewMethod.getMethod(); + final String view = viewMethod.getView(); + + MethodTransactionInfo transactionInfo = (MethodTransactionInfo) entry.getValue(); - for (Map.Entry<Method, MethodAttributeInfo> entry : attributes.entrySet()) { - MethodTransactionInfo value = (MethodTransactionInfo) entry.getValue(); + if (debug) log.debug("Transaction Attribute: " + method + " -- " + MethodInfoUtil.toString(transactionInfo)); -// logger.info(entry.getKey().toString() +" "+ value.transAttribute); - beanContext.setMethodTransactionAttribute(entry.getKey(), TransactionType.get(value.transAttribute)); + beanContext.setMethodTransactionAttribute(method, TransactionType.get(transactionInfo.transAttribute), view); } } + private static String getMethodInterface(MethodTransactionInfo value) { + // We can only do this because we have previously processed all the + // MethodTransactionInfo objects so there is one per method + // It makes code like this easier to handle + for (MethodInfo methodInfo : value.methods) { + return methodInfo.methodIntf; + } + + return null; + } + /** * This method splits the MethodTransactionInfo objects so that there is * exactly one MethodInfo per MethodTransactionInfo. A single MethodTransactionInfo Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/managed/ManagedContainer.java URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/managed/ManagedContainer.java?rev=1131304&r1=1131303&r2=1131304&view=diff ============================================================================== --- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/managed/ManagedContainer.java (original) +++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/managed/ManagedContainer.java Sat Jun 4 01:45:46 2011 @@ -358,7 +358,7 @@ public class ManagedContainer implements createContext.setCurrentAllowedStates(null); // Start transaction - TransactionPolicy txPolicy = createTransactionPolicy(createContext.getBeanContext().getTransactionType(callMethod), createContext); + TransactionPolicy txPolicy = createTransactionPolicy(createContext.getBeanContext().getTransactionType(callMethod, interfaceType), createContext); Instance instance = null; try { @@ -448,7 +448,7 @@ public class ManagedContainer implements } // Start transaction - TransactionPolicy txPolicy = createTransactionPolicy(callContext.getBeanContext().getTransactionType(callMethod), callContext); + TransactionPolicy txPolicy = createTransactionPolicy(callContext.getBeanContext().getTransactionType(callMethod, interfaceType), callContext); Object returnValue = null; boolean retain = false; @@ -550,7 +550,7 @@ public class ManagedContainer implements checkAuthorization(callMethod, interfaceType); // Start transaction - TransactionPolicy txPolicy = createTransactionPolicy(callContext.getBeanContext().getTransactionType(callMethod), callContext); + TransactionPolicy txPolicy = createTransactionPolicy(callContext.getBeanContext().getTransactionType(callMethod, interfaceType), callContext); Object returnValue = null; Instance instance = null; Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/singleton/SingletonContainer.java URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/singleton/SingletonContainer.java?rev=1131304&r1=1131303&r2=1131304&view=diff ============================================================================== --- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/singleton/SingletonContainer.java (original) +++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/singleton/SingletonContainer.java Sat Jun 4 01:45:46 2011 @@ -214,7 +214,7 @@ public class SingletonContainer implemen Object returnValue; try { - TransactionPolicy txPolicy = createTransactionPolicy(beanContext.getTransactionType(callMethod), callContext); + TransactionPolicy txPolicy = createTransactionPolicy(beanContext.getTransactionType(callMethod, callType), callContext); returnValue = null; try { Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java?rev=1131304&r1=1131303&r2=1131304&view=diff ============================================================================== --- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java (original) +++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java Sat Jun 4 01:45:46 2011 @@ -33,7 +33,6 @@ import javax.ejb.EJBContext; import javax.ejb.EJBException; import javax.ejb.EJBHome; import javax.ejb.EJBLocalHome; -import javax.ejb.NoSuchEJBException; import javax.ejb.RemoveException; import javax.ejb.SessionBean; import javax.ejb.SessionContext; @@ -369,7 +368,7 @@ public class StatefulContainer implement createContext.setCurrentAllowedStates(null); // Start transaction - TransactionPolicy txPolicy = createTransactionPolicy(createContext.getBeanContext().getTransactionType(callMethod), createContext); + TransactionPolicy txPolicy = createTransactionPolicy(createContext.getBeanContext().getTransactionType(callMethod, interfaceType), createContext); Instance instance = null; try { @@ -459,7 +458,7 @@ public class StatefulContainer implement } // Start transaction - TransactionPolicy txPolicy = createTransactionPolicy(callContext.getBeanContext().getTransactionType(callMethod), callContext); + TransactionPolicy txPolicy = createTransactionPolicy(callContext.getBeanContext().getTransactionType(callMethod, interfaceType), callContext); Object returnValue = null; boolean retain = false; @@ -561,7 +560,7 @@ public class StatefulContainer implement checkAuthorization(callMethod, interfaceType); // Start transaction - TransactionPolicy txPolicy = createTransactionPolicy(callContext.getBeanContext().getTransactionType(callMethod), callContext); + TransactionPolicy txPolicy = createTransactionPolicy(callContext.getBeanContext().getTransactionType(callMethod, interfaceType), callContext); Object returnValue = null; Instance instance = null; Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java?rev=1131304&r1=1131303&r2=1131304&view=diff ============================================================================== --- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java (original) +++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateless/StatelessContainer.java Sat Jun 4 01:45:46 2011 @@ -212,7 +212,7 @@ public class StatelessContainer implemen BeanContext beanContext = callContext.getBeanContext(); - TransactionPolicy txPolicy = createTransactionPolicy(beanContext.getTransactionType(callMethod), callContext); + TransactionPolicy txPolicy = createTransactionPolicy(beanContext.getTransactionType(callMethod, type), callContext); Object returnValue = null; try { Modified: openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/TransactionAttributesTest.java URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/TransactionAttributesTest.java?rev=1131304&r1=1131303&r2=1131304&view=diff ============================================================================== --- openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/TransactionAttributesTest.java (original) +++ openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/TransactionAttributesTest.java Sat Jun 4 01:45:46 2011 @@ -20,7 +20,9 @@ import static org.apache.openejb.assembl import junit.framework.TestCase; import org.apache.openejb.BeanContext; import org.apache.openejb.config.ConfigurationFactory; +import org.apache.openejb.core.ThreadContext; import org.apache.openejb.jee.EjbJar; +import org.apache.openejb.jee.InterceptorBinding; import org.apache.openejb.jee.StatelessBean; import org.apache.openejb.jee.ContainerTransaction; import org.apache.openejb.jee.TransAttribute; @@ -29,10 +31,18 @@ import static org.apache.openejb.assembl import org.apache.openejb.spi.ContainerSystem; import org.apache.openejb.loader.SystemInstance; +import javax.ejb.EJBTransactionRequiredException; import javax.ejb.Local; +import javax.ejb.LocalBean; import javax.ejb.Remote; import javax.ejb.TransactionAttribute; +import javax.interceptor.AroundInvoke; +import javax.interceptor.InvocationContext; +import javax.transaction.TransactionRequiredException; + import static javax.ejb.TransactionAttributeType.*; + +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; import java.util.List; @@ -42,6 +52,7 @@ import java.util.List; */ public class TransactionAttributesTest extends TestCase { private Map<Method, MethodAttributeInfo> attributes; + private Object bean; public void test() throws Exception { Assembler assembler = new Assembler(); @@ -64,6 +75,8 @@ public class TransactionAttributesTest e declared.add(new ContainerTransaction(TransAttribute.NEVER, Red.class.getName(), "Scarlet", "red")); declared.add(new ContainerTransaction(TransAttribute.REQUIRED, "Scarlet", Scarlet.class.getMethod("scarlet"))); + ejbJar.getAssemblyDescriptor().addInterceptorBinding(new InterceptorBinding("*", AttributeInterceptor.class.getName())); + EjbJarInfo ejbJarInfo = config.configureApplication(ejbJar); assembler.createApplication(ejbJarInfo); @@ -119,11 +132,29 @@ public class TransactionAttributesTest e BeanContext beanContext = system.getBeanContext(deploymentId); List<MethodTransactionInfo> infos = normalize(ejbJarInfo.methodTransactions); attributes = resolveAttributes(infos, beanContext); + bean = system.getBeanContext(deploymentId).getBusinessLocalBeanHome().create(); } - private void assertAttribute(String attribute, Method method) { + private void assertAttribute(String attribute, Method method) throws Exception { MethodTransactionInfo info = (MethodTransactionInfo) attributes.get(method); assertEquals(method.toString(), attribute, info.transAttribute); + + try { + final Object[] args = new Object[method.getParameterTypes().length]; + final Object result = method.invoke(bean, args); + assertEquals(attribute, result); + } catch (InvocationTargetException e) { + assertEquals(attribute, "Mandatory"); + assertTrue(e.getTargetException() instanceof EJBTransactionRequiredException); + } + } + + public static class AttributeInterceptor { + + @AroundInvoke + public Object invoke(InvocationContext context) throws Exception { + return ThreadContext.getThreadContext().getTransactionPolicy().getClass().getSimpleName().replace("Tx", ""); + } } @Local @@ -134,32 +165,33 @@ public class TransactionAttributesTest e public static interface ColorRemote { } + @LocalBean @TransactionAttribute(MANDATORY) public static class Color implements ColorLocal, ColorRemote { @TransactionAttribute(NEVER) - public void color(){} + public String color(){return null;} @TransactionAttribute(REQUIRES_NEW) - public void color(Object o){} + public String color(Object o){return null;} - public void color(String s){} - public void color(Boolean b){} - public void color(Integer i){} + public String color(String s){return null;} + public String color(Boolean b){return null;} + public String color(Integer i){return null;} } public static class Red extends Color { - public void color(Object o){super.color(o);} + public String color(Object o){return super.color(o);} @TransactionAttribute(REQUIRES_NEW) - public void red(){} + public String red(){return null;} - public void red(Object o){} - public void red(String s){} + public String red(Object o){return null;} + public String red(String s){return null;} } @@ -167,22 +199,22 @@ public class TransactionAttributesTest e public static class Crimson extends Red { - public void color(){} - public void color(String s){} + public String color(){return null;} + public String color(String s){return null;} @TransactionAttribute(REQUIRES_NEW) - public void crimson(){} + public String crimson(){return null;} - public void crimson(String s){} + public String crimson(String s){return null;} } @TransactionAttribute(NOT_SUPPORTED) public static class Scarlet extends Red { @TransactionAttribute(REQUIRES_NEW) - public void scarlet(){} + public String scarlet(){return null;} - public void scarlet(String s){} + public String scarlet(String s){return null;} } } Added: openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/InterfaceTransactionTest.java URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/InterfaceTransactionTest.java?rev=1131304&view=auto ============================================================================== --- openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/InterfaceTransactionTest.java (added) +++ openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateless/InterfaceTransactionTest.java Sat Jun 4 01:45:46 2011 @@ -0,0 +1,97 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.openejb.core.stateless; + +import junit.framework.TestCase; +import org.apache.openejb.OpenEJB; +import org.apache.openejb.jee.ContainerTransaction; +import org.apache.openejb.jee.EjbJar; +import org.apache.openejb.jee.Method; +import org.apache.openejb.jee.MethodIntf; +import org.apache.openejb.jee.StatelessBean; +import org.apache.openejb.jee.TransAttribute; +import org.apache.openejb.junit.ApplicationComposer; +import org.apache.openejb.junit.Module; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.ejb.EJB; +import javax.ejb.EJBException; +import javax.ejb.Local; +import javax.ejb.Remote; +import javax.ejb.Stateless; +import javax.transaction.Status; +import javax.transaction.SystemException; +import java.util.List; + +/** + * @version $Rev$ $Date$ + */ +@RunWith(ApplicationComposer.class) +public class InterfaceTransactionTest extends TestCase { + + @EJB + private OrangeRemote remote; + + @EJB + private OrangeLocal local; + + @Module + public EjbJar module() throws Exception { + final EjbJar ejbJar = new EjbJar(); + ejbJar.addEnterpriseBean(new StatelessBean(OrangeBean.class)); + + final Method remoteMethod = new Method("OrangeBean", "isInTransaction").withInterface(MethodIntf.REMOTE); + final Method localMethod = new Method("OrangeBean", "isInTransaction").withInterface(MethodIntf.LOCAL); + + final List<ContainerTransaction> transactions = ejbJar.getAssemblyDescriptor().getContainerTransaction(); + + transactions.add(new ContainerTransaction(TransAttribute.REQUIRED, remoteMethod)); + transactions.add(new ContainerTransaction(TransAttribute.SUPPORTS, localMethod)); + + return ejbJar; + } + + @Test + public void test() { + + assertTrue(remote.isInTransaction()); + assertFalse(local.isInTransaction()); + } + + @Local + public interface OrangeLocal { + public boolean isInTransaction(); + } + + @Remote + public static interface OrangeRemote extends OrangeLocal { + } + + @Stateless + public static class OrangeBean implements OrangeLocal, OrangeRemote { + + @Override + public boolean isInTransaction() { + try { + return Status.STATUS_ACTIVE == OpenEJB.getTransactionManager().getStatus(); + } catch (SystemException e) { + throw new EJBException(e); + } + } + } +} Modified: openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/Method.java URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/Method.java?rev=1131304&r1=1131303&r2=1131304&view=diff ============================================================================== --- openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/Method.java (original) +++ openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/Method.java Sat Jun 4 01:45:46 2011 @@ -180,6 +180,11 @@ public class Method { this.methodIntf = value; } + public Method withInterface(MethodIntf methodIntf) { + setMethodIntf(methodIntf); + return this; + } + public String getMethodName() { return methodName; } -- Shawn
