You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by db...@apache.org on 2010/06/09 05:50:37 UTC

svn commit: r952895 - 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/config/ openejb-core/src/main/java...

Author: dblevins
Date: Wed Jun  9 03:50:36 2010
New Revision: 952895

URL: http://svn.apache.org/viewvc?rev=952895&view=rev
Log:
Wonderful patch from Ivan for @AfterBegin, @BeforeCompletion, @AfterCompletion functionality.

Thank you, Ivan!

OPENEJB-1147 javax.ejb.AfterBegin
OPENEJB-1148 javax.ejb.AfterCompletion
OPENEJB-1149 javax.ejb.BeforeCompletion
OPENEJB-1215 <after-begin-method> element
OPENEJB-1216 <before-completion-method> element
OPENEJB-1217 <after-completion-method> element
OPENEJB-1218 @AfterBegin overriding via <after-begin-method>
OPENEJB-1219 @AfterCompletion overriding via <after-completion-method>
OPENEJB-1220 @BeforeCompletion overriding via <before-completion-method>

Added:
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppModulePreProcessor.java   (with props)
    openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/StatefulSessionSynchronizationTest.java   (with props)
    openejb/trunk/openejb3/container/openejb-jee/src/test/resources/ejb-session-synchronization.xml   (with props)
Modified:
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/DeploymentInfo.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorBindingBuilder.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorInfo.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/StatefulBeanInfo.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EjbJarInfoBuilder.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/rules/CheckCallbacks.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/CoreDeploymentInfo.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/InterceptorData.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/ReflectionInvocationContext.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/resources/org/apache/openejb/config/rules/Messages.properties
    openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/Interceptor.java
    openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/Session.java
    openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/SessionBean.java
    openejb/trunk/openejb3/container/openejb-jee/src/test/java/org/apache/openejb/jee/JeeTest.java

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/DeploymentInfo.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/DeploymentInfo.java?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/DeploymentInfo.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/DeploymentInfo.java Wed Jun  9 03:50:36 2010
@@ -30,7 +30,6 @@ import java.util.List;
 import java.util.Set;
 import java.util.Properties;
 import javax.naming.Context;
-import javax.ejb.ScheduleExpression;
 import javax.ejb.EJBHome;
 import javax.ejb.EJBLocalHome;
 

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorBindingBuilder.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorBindingBuilder.java?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorBindingBuilder.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorBindingBuilder.java Wed Jun  9 03:50:36 2010
@@ -84,6 +84,9 @@ public class InterceptorBindingBuilder {
             toMethods(clazz, info.prePassivate, interceptor.getPrePassivate());
             toMethods(clazz, info.postConstruct, interceptor.getPostConstruct());
             toMethods(clazz, info.preDestroy, interceptor.getPreDestroy());
+            toMethods(clazz, info.afterBegin, interceptor.getAfterBegin());
+            toMethods(clazz, info.beforeCompletion, interceptor.getBeforeCompletion());
+            toMethods(clazz, info.afterCompletion, interceptor.getAfterCompletion());
             interceptors.put(info.clazz, interceptor);
         }
     }
@@ -101,6 +104,10 @@ public class InterceptorBindingBuilder {
             StatefulBeanInfo stateful = (StatefulBeanInfo) beanInfo;
             toCallback(clazz, stateful.postActivate, beanAsInterceptor.getPostActivate());
             toCallback(clazz, stateful.prePassivate, beanAsInterceptor.getPrePassivate());
+
+            toCallback(clazz, stateful.afterBegin, beanAsInterceptor.getAfterBegin());
+            toCallback(clazz, stateful.beforeCompletion, beanAsInterceptor.getBeforeCompletion());
+            toCallback(clazz, stateful.afterCompletion, beanAsInterceptor.getAfterCompletion(), boolean.class);
         }
 
         for (Method method : deploymentInfo.getBeanClass().getMethods()) {
@@ -276,6 +283,9 @@ public class InterceptorBindingBuilder {
      *  - @PreDestroy <any-scope> void <method-name>()
      *  - @PrePassivate <any-scope> void <method-name>()
      *  - @PostActivate <any-scope> void <method-name>()
+     *  - @AfterBegin <any-scope> void <method-name>()
+     *  - @BeforeCompletion <any-scope> void <method-name>()
+     *  - @AfterCompletion <any-scope> void <method-name>(boolean)
      *
      * These apply to the bean class only, interceptor methods use InvocationContext as
      * a parameter.  The toMethods method is used for those.
@@ -284,10 +294,10 @@ public class InterceptorBindingBuilder {
      * @param callbackInfos
      * @param methods
      */
-    private void toCallback(Class clazz, List<CallbackInfo> callbackInfos, List<Method> methods) {
+    private void toCallback(Class clazz, List<CallbackInfo> callbackInfos, List<Method> methods, Class... parameterTypes) {
         for (CallbackInfo callbackInfo : callbackInfos) {
             try {
-                Method method = getMethod(clazz, callbackInfo.method);
+                Method method = getMethod(clazz, callbackInfo.method, parameterTypes);
                 if (callbackInfo.className == null){
                     methods.add(method);
                 } else if (method.getDeclaringClass().getName().equals(callbackInfo.className)){

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorInfo.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorInfo.java?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorInfo.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/InterceptorInfo.java Wed Jun  9 03:50:36 2010
@@ -30,4 +30,8 @@ public class InterceptorInfo extends Inf
 
     public final List<CallbackInfo> postActivate = new ArrayList<CallbackInfo>();
     public final List<CallbackInfo> prePassivate = new ArrayList<CallbackInfo>();
+
+    public final List<CallbackInfo> afterBegin = new ArrayList<CallbackInfo>();
+    public final List<CallbackInfo> beforeCompletion = new ArrayList<CallbackInfo>();
+    public final List<CallbackInfo> afterCompletion = new ArrayList<CallbackInfo>();
 }

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/StatefulBeanInfo.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/StatefulBeanInfo.java?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/StatefulBeanInfo.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/StatefulBeanInfo.java Wed Jun  9 03:50:36 2010
@@ -32,4 +32,8 @@ public class StatefulBeanInfo extends En
     public final List<RemoveMethodInfo> removeMethods = new ArrayList<RemoveMethodInfo>();
 
     public boolean localbean;
+
+    public final List<CallbackInfo> afterBegin = new ArrayList<CallbackInfo>();
+    public final List<CallbackInfo> beforeCompletion = new ArrayList<CallbackInfo>();
+    public final List<CallbackInfo> afterCompletion = new ArrayList<CallbackInfo>();
 }

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java Wed Jun  9 03:50:36 2010
@@ -135,6 +135,9 @@ import javax.ejb.TransactionManagement;
 import javax.ejb.TransactionManagementType;
 import javax.ejb.StatefulTimeout;
 import javax.ejb.AccessTimeout;
+import javax.ejb.AfterBegin;
+import javax.ejb.BeforeCompletion;
+import javax.ejb.AfterCompletion;
 import javax.interceptor.ExcludeClassInterceptors;
 import javax.interceptor.ExcludeDefaultInterceptors;
 import javax.interceptor.Interceptors;
@@ -231,6 +234,9 @@ public class AnnotationDeployer implemen
     }
 
     public static class DiscoverAnnotatedBeans implements DynamicDeployer {
+
+        private final AppModulePreProcessor.SessionSynchronizationProcessor sessionSynchronizationProcessor = new AppModulePreProcessor.SessionSynchronizationProcessor();
+
         public static final Set<String> knownResourceEnvTypes = new TreeSet<String>(asList(
                 "javax.ejb.SessionContext",
                 "javax.ejb.EntityContext",
@@ -295,7 +301,7 @@ public class AnnotationDeployer implemen
             if (clientModule.getApplicationClient() == null){
                 clientModule.setApplicationClient(new ApplicationClient());
             }
-            
+
             // Lots of jars have main classes so this might not even be an app client.
             // We're not going to scrape it for @LocalClient or @RemoteClient annotations
             // unless they flag us specifically by adding a META-INF/application-client.xml
@@ -413,7 +419,7 @@ public class AnnotationDeployer implemen
             }
 
             AbstractFinder finder = ejbModule.getFinder();
-            
+
             /* 19.2:  ejb-name: Default is the unqualified name of the bean class */
 
             EjbJar ejbJar = ejbModule.getEjbJar();
@@ -434,7 +440,7 @@ public class AnnotationDeployer implemen
                 if (enterpriseBean instanceof SessionBean) {
                     SessionBean sessionBean = (SessionBean) enterpriseBean;
                     sessionBean.setSessionType(SessionType.SINGLETON);
-                    
+
                     if (singleton.mappedName() != null) {
                         sessionBean.setMappedName(singleton.mappedName());
                     }
@@ -478,6 +484,7 @@ public class AnnotationDeployer implemen
                 }
                 if (enterpriseBean.getEjbClass() == null) {
                     enterpriseBean.setEjbClass(beanClass.getName());
+                    sessionSynchronizationProcessor.process(beanClass, enterpriseBean);
                 }
                 if (enterpriseBean instanceof SessionBean) {
                     SessionBean sessionBean = (SessionBean) enterpriseBean;
@@ -495,7 +502,7 @@ public class AnnotationDeployer implemen
 
                 // TODO: this is actually against the spec, but the requirement is rather silly
                 // (allowing @Stateful and @ManagedBean on the same class)
-                // If the TCK doesn't complain we should discourage it 
+                // If the TCK doesn't complain we should discourage it
                 if (!isValidEjbAnnotationUsage(ManagedBean.class, beanClass, ejbName, ejbModule)) continue;
 
                 EnterpriseBean enterpriseBean = ejbJar.getEnterpriseBean(ejbName);
@@ -536,11 +543,11 @@ public class AnnotationDeployer implemen
             }
 
             // https://issues.apache.org/jira/browse/OPENEJB-980
-            startupLogger.debug("Searching for inherited application exceptions (see OPENEJB-980) - it doesn't care whether inherited is true/false");  
+            startupLogger.debug("Searching for inherited application exceptions (see OPENEJB-980) - it doesn't care whether inherited is true/false");
             List<Class> appExceptions;
             appExceptions = finder.findInheritedAnnotatedClasses(ApplicationException.class);
             for (Class<?> exceptionClass : appExceptions) {
-                startupLogger.debug("...handling " + exceptionClass);  
+                startupLogger.debug("...handling " + exceptionClass);
                 if (assemblyDescriptor.getApplicationException(exceptionClass) == null) {
                     ApplicationException annotation = exceptionClass.getAnnotation(ApplicationException.class);
                     // OPENEJB-980
@@ -551,7 +558,7 @@ public class AnnotationDeployer implemen
                             annotation = parentExceptionClass.getAnnotation(ApplicationException.class);
                         }
                     }
-                    startupLogger.debug("...adding " + exceptionClass + " with rollback=" + annotation.rollback());  
+                    startupLogger.debug("...adding " + exceptionClass + " with rollback=" + annotation.rollback());
                     assemblyDescriptor.addApplicationException(exceptionClass, annotation.rollback());
                 }
             }
@@ -702,7 +709,7 @@ public class AnnotationDeployer implemen
 
             if (clientModule.getMainClass() != null){
                 String className = clientModule.getMainClass();
-                
+
                 // OPENEJB-1063: a Main-Class should use "." instead of "/"
                 // it wasn't check before jdk 1.5 so we can get old module with
                 // bad format http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4986512
@@ -1166,7 +1173,7 @@ public class AnnotationDeployer implemen
                 }
 
                 /*
-                 * Add any interceptors they may have referenced in xml but did not declare 
+                 * Add any interceptors they may have referenced in xml but did not declare
                  */
                 for (InterceptorBinding binding : assemblyDescriptor.getInterceptorBinding()) {
                     EjbJar ejbJar = ejbModule.getEjbJar();
@@ -1754,7 +1761,7 @@ public class AnnotationDeployer implemen
                 /**
                  * OK, now start checking the metadata of the interfaces implemented by this class
                  */
-            
+
 
                 /**
                  * This set holds the list of interfaces that the bean implements
@@ -2078,6 +2085,36 @@ public class AnnotationDeployer implemen
                 org.apache.openejb.jee.Session session = (org.apache.openejb.jee.Session) bean;
 
                 /*
+                 * @AfterBegin
+                 */
+                LifecycleCallback afterBegin = getFirst(session.getAfterBegin());
+                if (afterBegin == null) {
+                    for (Method method : classFinder.findAnnotatedMethods(AfterBegin.class)) {
+                        session.getAfterBegin().add(new LifecycleCallback(method));
+                    }
+                }
+
+                /*
+                 * @BeforeCompletion
+                 */
+                LifecycleCallback beforeCompletion = getFirst(session.getBeforeCompletion());
+                if (beforeCompletion == null) {
+                    for (Method method : classFinder.findAnnotatedMethods(BeforeCompletion.class)) {
+                        session.getBeforeCompletion().add(new LifecycleCallback(method));
+                    }
+                }
+
+                /*
+                 * @AfterCompletion
+                 */
+                LifecycleCallback afterCompletion = getFirst(session.getAfterCompletion());
+                if (afterCompletion == null) {
+                    for (Method method : classFinder.findAnnotatedMethods(AfterCompletion.class)) {
+                        session.getAfterCompletion().add(new LifecycleCallback(method));
+                    }
+                }
+
+                /*
                  * @PostActivate
                  */
                 LifecycleCallback postActivate = getFirst(session.getPostActivate());
@@ -2933,7 +2970,7 @@ public class AnnotationDeployer implemen
          */
         private void processWebServiceClientHandlers(JndiConsumer consumer, ClassLoader classLoader) throws OpenEJBException {
             if (SystemInstance.get().hasProperty("openejb.geronimo")) return;
-            
+
             Set<Class<?>> processedClasses = new HashSet<Class<?>>();
             Set<Class<?>> handlerClasses = new HashSet<Class<?>>();
             do {

Added: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppModulePreProcessor.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppModulePreProcessor.java?rev=952895&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppModulePreProcessor.java (added)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppModulePreProcessor.java Wed Jun  9 03:50:36 2010
@@ -0,0 +1,83 @@
+/**
+ *  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.config;
+
+import javax.ejb.SessionSynchronization;
+
+import org.apache.openejb.OpenEJBException;
+import org.apache.openejb.jee.EnterpriseBean;
+import org.apache.openejb.jee.LifecycleCallback;
+import org.apache.openejb.jee.SessionBean;
+import org.apache.openejb.jee.SessionType;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class AppModulePreProcessor implements DynamicDeployer {
+
+    private SessionSynchronizationProcessor sessionSynchronizationProcessor = new SessionSynchronizationProcessor();
+
+    @Override
+    public AppModule deploy(AppModule appModule) throws OpenEJBException {
+        for (EjbModule ejbModule : appModule.getEjbModules()) {
+            ClassLoader classLoader = ejbModule.getClassLoader();
+            for (EnterpriseBean bean : ejbModule.getEjbJar().getEnterpriseBeans()) {
+                if (bean.getEjbClass() == null) {
+                    continue;
+                }
+                Class<?> clazz;
+                try {
+                    clazz = classLoader.loadClass(bean.getEjbClass());
+                } catch (ClassNotFoundException e) {
+                    throw new OpenEJBException("Unable to load bean class: " + bean.getEjbClass(), e);
+                }
+                sessionSynchronizationProcessor.process(clazz, bean);
+            }
+
+        }
+        return appModule;
+    }
+
+    public static class SessionSynchronizationProcessor {
+
+        public void process(Class<?> clazz, EnterpriseBean enterpriseBean) {
+            if (!(enterpriseBean instanceof SessionBean)) {
+                return;
+            }
+            SessionBean sessionBean = (SessionBean) enterpriseBean;
+            if (sessionBean.getSessionType() != SessionType.STATEFUL) {
+                return;
+            }
+            if (SessionSynchronization.class.isAssignableFrom(clazz)) {
+                sessionBean.getAfterBegin().add(new LifecycleCallback(clazz.getName(), "afterBegin"));
+                sessionBean.getBeforeCompletion().add(new LifecycleCallback(clazz.getName(), "beforeCompletion"));
+                sessionBean.getAfterCompletion().add(new LifecycleCallback(clazz.getName(), "afterCompletion"));
+            } else {
+                if (sessionBean.getAfterBeginMethod() != null) {
+                    sessionBean.getAfterBegin().add(new LifecycleCallback(clazz.getName(), sessionBean.getAfterBeginMethod().getMethodName()));
+                }
+                if (sessionBean.getBeforeCompletionMethod() != null) {
+                    sessionBean.getBeforeCompletion().add(new LifecycleCallback(clazz.getName(), sessionBean.getBeforeCompletionMethod().getMethodName()));
+                }
+                if (sessionBean.getAfterCompletionMethod() != null) {
+                    sessionBean.getAfterCompletion().add(new LifecycleCallback(clazz.getName(), sessionBean.getAfterCompletionMethod().getMethodName()));
+                }
+            }
+        }
+    }
+}

Propchange: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppModulePreProcessor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java Wed Jun  9 03:50:36 2010
@@ -127,6 +127,8 @@ public class ConfigurationFactory implem
 
         Chain chain = new Chain();
 
+        chain.add(new AppModulePreProcessor());
+
         chain.add(new GeneratedClientModules.Add());
 
         chain.add(new ReadDescriptors());
@@ -287,7 +289,7 @@ public class ConfigurationFactory implem
      * the assembler needs to actually build the contianer system
      *
      * This method is called by the Assembler once at startup.
-     * 
+     *
      * @return
      * @throws OpenEJBException
      */
@@ -296,7 +298,7 @@ public class ConfigurationFactory implem
         if (sys != null) {
             return sys;
         }
-        
+
         if (configLocation != null) {
             openejb = JaxbOpenejb.readConfig(configLocation);
         } else {
@@ -642,7 +644,7 @@ public class ConfigurationFactory implem
      * As in:
      *
      *   - META-INF/<provider>/service-jar.xml
-     * 
+     *
      */
     static {
         defaultProviders.put(MdbContainerInfo.class, new DefaultService("MESSAGE", Container.class));
@@ -693,7 +695,7 @@ public class ConfigurationFactory implem
      *
      * The end result is a canonical (i.e. flattened) ServiceInfo
      * The ServiceInfo will be of a specific type (ContainerInfo, ResourceInfo, etc)
-     * 
+     *
      * @param service
      * @param infoType
      * @param <T>

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EjbJarInfoBuilder.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EjbJarInfoBuilder.java?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EjbJarInfoBuilder.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EjbJarInfoBuilder.java Wed Jun  9 03:50:36 2010
@@ -296,6 +296,10 @@ public class EjbJarInfoBuilder {
             copyCallbacks(s.getPostActivate(), info.postActivate);
             copyCallbacks(s.getPrePassivate(), info.prePassivate);
 
+            copyCallbacks(s.getAfterBegin(), info.afterBegin);
+            copyCallbacks(s.getBeforeCompletion(), info.beforeCompletion);
+            copyCallbacks(s.getAfterCompletion(), info.afterCompletion);
+
             ejbJar.interceptors.add(info);
         }
 
@@ -490,6 +494,10 @@ public class EjbJarInfoBuilder {
             copyCallbacks(s.getPostActivate(), stateful.postActivate);
             copyCallbacks(s.getPrePassivate(), stateful.prePassivate);
 
+            copyCallbacks(s.getAfterBegin(), stateful.afterBegin);
+            copyCallbacks(s.getBeforeCompletion(), stateful.beforeCompletion);
+            copyCallbacks(s.getAfterCompletion(), stateful.afterCompletion);
+
             for (InitMethod initMethod : s.getInitMethod()) {
                 InitMethodInfo init = new InitMethodInfo();
                 init.beanMethod = toInfo(initMethod.getBeanMethod());
@@ -523,7 +531,7 @@ public class EjbJarInfoBuilder {
             ConcurrencyType type = s.getConcurrencyType();
             bean.concurrencyType = (type != null) ? type.toString() : ConcurrencyType.CONTAINER.toString();
             bean.loadOnStartup = s.getLoadOnStartup();
-            // See JndiEncInfoBuilder.buildDependsOnRefs for processing of DependsOn 
+            // See JndiEncInfoBuilder.buildDependsOnRefs for processing of DependsOn
             // bean.dependsOn.addAll(s.getDependsOn());
             ((SingletonBeanInfo)bean).localbean = s.getLocalBean() != null;
         } else {

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/rules/CheckCallbacks.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/rules/CheckCallbacks.java?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/rules/CheckCallbacks.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/rules/CheckCallbacks.java Wed Jun  9 03:50:36 2010
@@ -33,11 +33,16 @@ import org.apache.openejb.OpenEJBExcepti
 import org.apache.xbean.finder.ClassFinder;
 
 import javax.interceptor.InvocationContext;
+import javax.ejb.AfterBegin;
+import javax.ejb.AfterCompletion;
+import javax.ejb.BeforeCompletion;
 import javax.ejb.PrePassivate;
 import javax.ejb.PostActivate;
 import javax.ejb.Remove;
 import javax.ejb.Init;
+import javax.ejb.SessionSynchronization;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.util.List;
 import java.util.ArrayList;
 
@@ -79,7 +84,35 @@ public class CheckCallbacks extends Vali
                     for (LifecycleCallback callback : session.getPostActivate()) {
                         checkCallback(ejbClass, "PostActivate", callback, bean);
                     }
+
+                    checkSessionSynchronization(ejbClass, session);
+
+                    for (LifecycleCallback callback : session.getAfterBegin()) {
+                        checkCallback(ejbClass, "AfterBegin", callback, bean);
+                    }
+
+                    for (LifecycleCallback callback : session.getBeforeCompletion()) {
+                        checkCallback(ejbClass, "BeforeCompletion", callback, bean);
+                    }
+
+                    for (LifecycleCallback callback : session.getAfterCompletion()) {
+                        checkCallback(ejbClass, "AfterCompletion", callback, bean, boolean.class);
+                    }
+
                 } else {
+
+                    for (LifecycleCallback callback : session.getAfterBegin()) {
+                        ignoredStatefulAnnotation("afterBegin", bean, callback.getMethodName(), session.getSessionType().getName());
+                    }
+
+                    for (LifecycleCallback callback : session.getBeforeCompletion()) {
+                        ignoredStatefulAnnotation("beforeCompletion", bean, callback.getMethodName(), session.getSessionType().getName());
+                    }
+
+                    for (LifecycleCallback callback : session.getAfterCompletion()) {
+                        ignoredStatefulAnnotation("afterCompletion", bean, callback.getMethodName(), session.getSessionType().getName());
+                    }
+
                     for (LifecycleCallback callback : session.getPrePassivate()) {
                         ignoredStatefulAnnotation("PrePassivate", bean, callback.getMethodName(), session.getSessionType().getName());
                     }
@@ -114,6 +147,18 @@ public class CheckCallbacks extends Vali
                 for (Method method : finder.findAnnotatedMethods(Init.class)) {
                     ignoredStatefulAnnotation("Init", bean, method.getName(), bean.getClass().getSimpleName());
                 }
+
+                for (Method method : finder.findAnnotatedMethods(AfterBegin.class)) {
+                    ignoredStatefulAnnotation("afterBegin", bean, method.getName(), bean.getClass().getSimpleName());
+                }
+
+                for (Method method : finder.findAnnotatedMethods(BeforeCompletion.class)) {
+                    ignoredStatefulAnnotation("beforeCompletion", bean, method.getName(), bean.getClass().getSimpleName());
+                }
+
+                for (Method method : finder.findAnnotatedMethods(AfterCompletion.class)) {
+                    ignoredStatefulAnnotation("afterCompletion", bean, method.getName(), bean.getClass().getSimpleName());
+                }
             }
 
             if (bean instanceof TimerConsumer) {
@@ -149,6 +194,18 @@ public class CheckCallbacks extends Vali
             for (LifecycleCallback callback : interceptor.getPostActivate()) {
                 checkCallback(interceptorClass, "PostActivate", callback, interceptor);
             }
+
+            for (LifecycleCallback callback : interceptor.getAfterBegin()) {
+                checkCallback(interceptorClass, "AfterBegin", callback, interceptor);
+            }
+
+            for (LifecycleCallback callback : interceptor.getBeforeCompletion()) {
+                checkCallback(interceptorClass, "BeforeCompletion", callback, interceptor);
+            }
+
+            for (LifecycleCallback callback : interceptor.getAfterCompletion()) {
+                checkCallback(interceptorClass, "AfterCompletion", callback, interceptor);
+            }
         }
     }
 
@@ -190,21 +247,26 @@ public class CheckCallbacks extends Vali
         warn(bean, "ignoredStatefulAnnotation", annotationType, beanType, methodName);
     }
 
-    private void checkCallback(Class ejbClass, String type, CallbackMethod callback, EnterpriseBean bean) {
+    private void checkCallback(Class ejbClass, String type, CallbackMethod callback, EnterpriseBean bean, Class... parameterTypes) {
         try {
-            Method method = getMethod(ejbClass, callback.getMethodName());
+            Method method = getMethod(ejbClass, callback.getMethodName(), parameterTypes);
 
             Class<?> returnType = method.getReturnType();
 
             if (!returnType.equals(Void.TYPE)) {
                 fail(bean, "callback.badReturnType", type, callback.getMethodName(), returnType.getName(), callback.getClassName());
             }
+
+            int methodModifiers = method.getModifiers();
+            if (Modifier.isFinal(methodModifiers) || Modifier.isStatic(methodModifiers)) {
+                fail(bean, "callback.badModifier", type, callback.getMethodName(), callback.getClassName());
+            }
         } catch (NoSuchMethodException e) {
             List<Method> possibleMethods = getMethods(ejbClass, callback.getMethodName());
 
             if (possibleMethods.size() == 0) {
                 fail(bean, "callback.missing", type, callback.getMethodName(), callback.getClassName());
-            } else if (possibleMethods.size() == 1) {
+            } else if (possibleMethods.size() != parameterTypes.length) {
                 fail(bean, "callback.invalidArguments", type, callback.getMethodName(), getParameters(possibleMethods.get(0)), callback.getClassName());
             } else {
                 fail(bean, "callback.missing.possibleTypo", type, callback.getMethodName(), possibleMethods.size(), callback.getClassName());
@@ -234,6 +296,19 @@ public class CheckCallbacks extends Vali
         }
     }
 
+    private void checkSessionSynchronization(Class ejbClass, SessionBean bean) {
+        if (SessionSynchronization.class.isAssignableFrom(ejbClass)) {
+            if (bean.getAfterBeginMethod() != null || bean.getBeforeCompletionMethod() != null || bean.getAfterCompletionMethod() != null) {
+                fail(bean, "calllback.invalidSessionSynchronizationUse", ejbClass.getName());
+            } else {
+                ClassFinder classFinder = new ClassFinder(ejbClass);
+                if (classFinder.findAnnotatedMethods(AfterBegin.class).size() > 0 || classFinder.findAnnotatedMethods(AfterBegin.class).size() > 0
+                        || classFinder.findAnnotatedMethods(AfterBegin.class).size() > 0) {
+                    fail(bean, "callback.sessionSynchronization.invalidUse", ejbClass.getName());
+                }
+            }
+        }
+    }
 
     private void checkTimeOut(Class ejbClass, NamedMethod timeout, EnterpriseBean bean) {
         if (timeout == null) return;

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/CoreDeploymentInfo.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/CoreDeploymentInfo.java?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/CoreDeploymentInfo.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/CoreDeploymentInfo.java Wed Jun  9 03:50:36 2010
@@ -34,7 +34,6 @@ import javax.ejb.EJBLocalHome;
 import javax.ejb.EJBLocalObject;
 import javax.ejb.EJBObject;
 import javax.ejb.MessageDrivenBean;
-import javax.ejb.SessionSynchronization;
 import javax.ejb.TimedObject;
 import javax.ejb.Timer;
 import javax.naming.Context;
@@ -82,6 +81,10 @@ public class CoreDeploymentInfo implemen
     private final List<Method> postActivate = new ArrayList<Method>();
     private final List<Method> prePassivate = new ArrayList<Method>();
 
+    private final List<Method> afterBegin = new ArrayList<Method>();
+    private final List<Method> beforeCompletion= new ArrayList<Method>();
+    private final List<Method> afterCompletion = new ArrayList<Method>();
+
     private final List<Method> removeMethods = new ArrayList<Method>();
 
     private final Set<String> dependsOn = new LinkedHashSet<String>();
@@ -124,7 +127,7 @@ public class CoreDeploymentInfo implemen
     private final List<InterceptorData> callbackInterceptors = new ArrayList<InterceptorData>();
     private final Set<InterceptorData> instanceScopedInterceptors = new HashSet<InterceptorData>();
 
-    private final List<InterceptorInstance> systemInterceptors = new ArrayList<InterceptorInstance>(); 
+    private final List<InterceptorInstance> systemInterceptors = new ArrayList<InterceptorInstance>();
     private final Map<Method, Method> methodMap = new HashMap<Method, Method>();
     private final Map<String, String> securityRoleReferenceMap = new HashMap<String, String>();
     private String jarPath;
@@ -159,7 +162,7 @@ public class CoreDeploymentInfo implemen
         switch(interfaceType){
             case BUSINESS_REMOTE: return getBusinessRemoteInterfaces();
             case BUSINESS_LOCAL: return getBusinessLocalInterfaces();
-            default: 
+            default:
             List<Class> interfaces = new ArrayList<Class>();
             interfaces.add(getInterface(interfaceType));
             return interfaces;
@@ -705,6 +708,18 @@ public class CoreDeploymentInfo implemen
         return removeMethods;
     }
 
+    public List<Method> getAfterBegin() {
+        return afterBegin;
+    }
+
+    public List<Method> getBeforeCompletion() {
+        return beforeCompletion;
+    }
+
+    public List<Method> getAfterCompletion() {
+        return afterCompletion;
+    }
+
     private final Map<Method, Boolean> removeExceptionPolicy = new HashMap<Method,Boolean>();
 
     public void setRetainIfExeption(Method removeMethod, boolean retain){
@@ -744,7 +759,7 @@ public class CoreDeploymentInfo implemen
     }
 
     public void addSystemInterceptor(Object interceptor) {
-        systemInterceptors.add(new InterceptorInstance(interceptor));    
+        systemInterceptors.add(new InterceptorInstance(interceptor));
     }
 
     public List<InterceptorInstance> getSystemInterceptors() {
@@ -770,7 +785,7 @@ public class CoreDeploymentInfo implemen
         if (systemInterceptors.size() <= 0) return interceptors;
 
         // we have system interceptors to add to the beginning of the stack
-        
+
         List<InterceptorData> datas = new ArrayList<InterceptorData>(systemInterceptors.size() + interceptors.size());
 
         for (InterceptorInstance instance : systemInterceptors) {
@@ -778,7 +793,7 @@ public class CoreDeploymentInfo implemen
         }
 
         datas.addAll(interceptors);
-        
+
         return datas;
     }
 
@@ -1123,7 +1138,7 @@ public class CoreDeploymentInfo implemen
     }
 
     public boolean isSessionSynchronized() {
-        return !isBeanManagedTransaction() && SessionSynchronization.class.isAssignableFrom(beanClass);
+        return !isBeanManagedTransaction();
     }
 
     public boolean isLocalbean() {

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/InterceptorData.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/InterceptorData.java?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/InterceptorData.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/InterceptorData.java Wed Jun  9 03:50:36 2010
@@ -25,6 +25,9 @@ import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 import javax.ejb.PostActivate;
 import javax.ejb.PrePassivate;
+import javax.ejb.AfterBegin;
+import javax.ejb.BeforeCompletion;
+import javax.ejb.AfterCompletion;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
@@ -45,6 +48,10 @@ public class InterceptorData {
     private final List<Method> postActivate = new ArrayList<Method>();
     private final List<Method> prePassivate = new ArrayList<Method>();
 
+    private final List<Method> afterBegin = new ArrayList<Method>();
+    private final List<Method> beforeCompletion = new ArrayList<Method>();
+    private final List<Method> afterCompletion = new ArrayList<Method>();
+
     public InterceptorData(Class clazz) {
         this.clazz = clazz;
     }
@@ -73,6 +80,18 @@ public class InterceptorData {
         return prePassivate;
     }
 
+    public List<Method> getAfterBegin() {
+        return afterBegin;
+    }
+
+    public List<Method> getBeforeCompletion() {
+        return beforeCompletion;
+    }
+
+    public List<Method> getAfterCompletion() {
+        return afterCompletion;
+    }
+
     public List<Method> getMethods(Operation operation) {
         switch(operation) {
             case BUSINESS: return getAroundInvoke();
@@ -82,9 +101,9 @@ public class InterceptorData {
             case PRE_DESTROY: return getPreDestroy();
             case ACTIVATE: return getPostActivate();
             case PASSIVATE: return getPrePassivate();
-            case AFTER_BEGIN: return getAroundInvoke();
-            case AFTER_COMPLETION: return getAroundInvoke();
-            case BEFORE_COMPLETION: return getAroundInvoke();
+            case AFTER_BEGIN: return getAfterBegin();
+            case AFTER_COMPLETION: return getAfterCompletion();
+            case BEFORE_COMPLETION: return getBeforeCompletion();
         }
         return Collections.EMPTY_LIST;
     }
@@ -114,6 +133,9 @@ public class InterceptorData {
         data.preDestroy.addAll(finder.findAnnotatedMethods(PreDestroy.class));
         data.postActivate.addAll(finder.findAnnotatedMethods(PostActivate.class));
         data.prePassivate.addAll(finder.findAnnotatedMethods(PrePassivate.class));
+        data.afterBegin.addAll(finder.findAnnotatedMethods(AfterBegin.class));
+        data.beforeCompletion.addAll(finder.findAnnotatedMethods(BeforeCompletion.class));
+        data.afterCompletion.addAll(finder.findAnnotatedMethods(AfterCompletion.class));
 
         return data;
     }

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/ReflectionInvocationContext.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/ReflectionInvocationContext.java?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/ReflectionInvocationContext.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/interceptor/ReflectionInvocationContext.java Wed Jun  9 03:50:36 2010
@@ -71,6 +71,7 @@ public class ReflectionInvocationContext
     }
 
     public Object[] getParameters() {
+        //TODO Need to figure out what is going on with afterCompletion call back here ?
         if (operation.isCallback()) {
             throw new IllegalStateException(getIllegalParameterAccessMessage());
         }
@@ -124,10 +125,10 @@ public class ReflectionInvocationContext
             Object nextInstance = interceptor.getInstance();
             Method nextMethod = interceptor.getMethod();
 
-            if (nextMethod.getParameterTypes().length > 0){
+            if (nextMethod.getParameterTypes().length == 1 && nextMethod.getParameterTypes()[0] == InvocationContext.class) {
                 return new InterceptorInvocation(nextInstance, nextMethod, this);
             } else {
-                return new LifecycleInvocation(nextInstance, nextMethod, this);
+                return new LifecycleInvocation(nextInstance, nextMethod, this, parameters);
             }
         } else if (method != null) {
             return new BeanInvocation(target, method, parameters);
@@ -198,8 +199,8 @@ public class ReflectionInvocationContext
     private static class LifecycleInvocation extends Invocation {
         private final InvocationContext invocationContext;
 
-        public LifecycleInvocation(Object target, Method method, InvocationContext invocationContext) {
-            super(target, method, new Object[] {});
+        public LifecycleInvocation(Object target, Method method, InvocationContext invocationContext, Object[] args) {
+            super(target, method, args);
             this.invocationContext = invocationContext;
         }
 

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=952895&r1=952894&r2=952895&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 Wed Jun  9 03:50:36 2010
@@ -33,7 +33,6 @@ import javax.ejb.EJBLocalHome;
 import javax.ejb.RemoveException;
 import javax.ejb.SessionBean;
 import javax.ejb.SessionContext;
-import javax.ejb.SessionSynchronization;
 import javax.naming.Context;
 import javax.naming.NamingException;
 import javax.persistence.EntityManager;
@@ -362,7 +361,7 @@ public class StatefulContainer implement
 
                 // Register for synchronization callbacks
                 registerSessionSynchronization(instance, createContext);
-              
+
                 // Invoke create for legacy beans
                 if (!callMethod.getDeclaringClass().equals(DeploymentInfo.BusinessLocalHome.class) &&
                         !callMethod.getDeclaringClass().equals(DeploymentInfo.BusinessRemoteHome.class) &&
@@ -465,7 +464,7 @@ public class StatefulContainer implement
                 if (declaringClass.equals(EJBHome.class) || declaringClass.equals(EJBLocalHome.class)){
                     args = new Object[]{};
                 }
-                
+
                 // Initialize interceptor stack
                 List<InterceptorData> interceptors = deploymentInfo.getMethodInterceptors(runMethod);
                 InterceptorStack interceptorStack = new InterceptorStack(instance.bean, runMethod, Operation.REMOVE, interceptors, instance.interceptors);
@@ -881,7 +880,7 @@ public class StatefulContainer implement
     /**
      * SessionSynchronizationCoordinator handles afterBegin, beforeCompletion and afterCompletion callbacks.
      *
-     * This class also is responsible for calling releaseInstance after the transaction completes. 
+     * This class also is responsible for calling releaseInstance after the transaction completes.
      */
     private class SessionSynchronizationCoordinator implements TransactionSynchronization {
         private final Map<Object, Synchronization> registry = new HashMap<Object, Synchronization>();
@@ -934,10 +933,8 @@ public class StatefulContainer implement
             ThreadContext oldCallContext = ThreadContext.enter(callContext);
             try {
 
-                Method afterBegin = SessionSynchronization.class.getMethod("afterBegin");
-
-                List<InterceptorData> interceptors = deploymentInfo.getMethodInterceptors(afterBegin);
-                InterceptorStack interceptorStack = new InterceptorStack(instance.bean, afterBegin, Operation.AFTER_BEGIN, interceptors, instance.interceptors);
+                List<InterceptorData> interceptors = deploymentInfo.getCallbackInterceptors();
+                InterceptorStack interceptorStack = new InterceptorStack(instance.bean, null, Operation.AFTER_BEGIN, interceptors, instance.interceptors);
                 interceptorStack.invoke();
 
             } catch (Exception e) {
@@ -973,10 +970,9 @@ public class StatefulContainer implement
                 try {
                     instance.setInUse(true);
 
-                    Method beforeCompletion = SessionSynchronization.class.getMethod("beforeCompletion");
-
-                    List<InterceptorData> interceptors = instance.deploymentInfo.getMethodInterceptors(beforeCompletion);
-                    InterceptorStack interceptorStack = new InterceptorStack(instance.bean, beforeCompletion, Operation.BEFORE_COMPLETION, interceptors, instance.interceptors);
+                    CoreDeploymentInfo deploymentInfo = instance.deploymentInfo;
+                    List<InterceptorData> interceptors = deploymentInfo.getCallbackInterceptors();
+                    InterceptorStack interceptorStack = new InterceptorStack(instance.bean, null, Operation.BEFORE_COMPLETION, interceptors, instance.interceptors);
                     interceptorStack.invoke();
 
                     instance.setInUse(false);
@@ -1014,10 +1010,10 @@ public class StatefulContainer implement
                 try {
                     instance.setInUse(true);
                     if (synchronization.isCallSessionSynchronization()) {
-                        Method afterCompletion = SessionSynchronization.class.getMethod("afterCompletion", boolean.class);
 
-                        List<InterceptorData> interceptors = instance.deploymentInfo.getMethodInterceptors(afterCompletion);
-                        InterceptorStack interceptorStack = new InterceptorStack(instance.bean, afterCompletion, Operation.AFTER_COMPLETION, interceptors, instance.interceptors);
+                        CoreDeploymentInfo deploymentInfo = instance.deploymentInfo;
+                        List<InterceptorData> interceptors = deploymentInfo.getCallbackInterceptors();
+                        InterceptorStack interceptorStack = new InterceptorStack(instance.bean, null, Operation.AFTER_COMPLETION, interceptors, instance.interceptors);
                         interceptorStack.invoke(status == Status.COMMITTED);
                     }
                     instance.setTransaction(null);
@@ -1109,7 +1105,7 @@ public class StatefulContainer implement
                 ThreadContext.exit(oldContext);
             }
         }
-    }    
+    }
 
     private static class Data {
         private final Index<Method, MethodType> methodIndex;

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/resources/org/apache/openejb/config/rules/Messages.properties
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/resources/org/apache/openejb/config/rules/Messages.properties?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/resources/org/apache/openejb/config/rules/Messages.properties (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/resources/org/apache/openejb/config/rules/Messages.properties Wed Jun  9 03:50:36 2010
@@ -193,6 +193,11 @@
 2.callback.badReturnType = {0} method must return 'void': method {1} returns {2}
 3.callback.badReturnType = {0} method "{1}" in class {3} illegally returns {2} instead of void.  Change the method signature to "void {1}()"
 
+# fail(bean, "callback.badModifier", type, callback.getMethodName(), callback.getClassName());
+1.callback.badModifier = {0} method must not be final and static
+2.callback.badModifier = {0} method must not be final and static : method {1}
+3.callback.badModifier = {0} method "{1}" in class {2} must not be final and static
+
 # fail(bean, "callback.missing", type, callback.getMethodName(), callback.getClassName());
 1.callback.missing = {0} method missing
 2.callback.missing = {0} method missing: "{1}" in class {2}
@@ -208,6 +213,11 @@
 2.callback.missing.possibleTypo = {0} method missing or invalid: looked for "void {1}()" in class {3}
 3.callback.missing.possibleTypo = {0} method missing or invalid.  There are {2} methods with the name "{1}" visible in class {3}, none have the required signature of "void {1}()"
 
+# fail(bean, "callback.sessionSynchronization.invalidUse", class)
+1.callback.sessionSynchronization.invalidUse = Session synchronization annotations and configurations in deployment plan should not be used while SessionSynchronization interface is implemented by the bean class.
+2.callback.sessionSynchronization.invalidUse = Session synchronization annotations and configurations in deployment plan should not be used while SessionSynchronization interface is implemented by the bean class {0}.
+3.callback.sessionSynchronization.invalidUse = Session synchronization annotations and configurations in deployment plan should not be used while SessionSynchronization interface is implemented by the bean class {0}.
+
 # fail(bean, "timeout.badReturnType", callback.getMethodName(), returnType.getName());
 1.timeout.badReturnType = Timeout method must return 'void'
 2.timeout.badReturnType = Timeout method must return 'void': method {0} returns {1}
@@ -769,6 +779,34 @@ Which can then be implemented by the {0}
 2.ann.ejb.notInterface = @EJB mistakenly refers to a non-interface.  Use the beans business interface instead
 3.ann.ejb.notInterface = The @EJB annotation cannot be used to directly refer to the bean class itself and must instead refer to the bean using one of its business interfaces.  Change the type of the {1} reference from {0} to a business interface of that bean.
 
+1.ann.sessionsynchronization.invalidModifier = @AfterBegin, @BeforeCompletion and @AfterCompletion must not be used on methods declared as final or static. 
+2.ann.sessionsynchronization.invalidModifier = {2} must not be used on the method {1} declared as final or static in bean class {0}.
+3.ann.sessionsynchronization.invalidModifier = {2} must not be used on the method {1} declared as final or static in bean class {0}.
+
+1.ann.sessionsynchronization.invalidReturnValue = The return type of the method annotated with @AfterBegin, @BeforeCompletion and @AfterCompletion must be void.
+2.ann.sessionsynchronization.invalidReturnValue = The return type of the method {1} annotated with {2} must be void in bean class {0}.
+3.ann.sessionsynchronization.invalidReturnValue = The return type of the method {1} annotated with {2} must be void in bean class {0}.
+
+1.ann.sessionsynchronization.noBooleanParameter = The method annotated with @AfterCompletion must take a single argument of type boolean.
+2.ann.sessionsynchronization.noBooleanParameter = The method {1} annotated with @AfterCompletion must take a single argument of type boolean in bean class {0}.
+3.ann.sessionsynchronization.noBooleanParameter = The method {1} annotated with @AfterCompletion must take a single argument of type boolean in bean class {0}.
+
+1.ann.sessionsynchronization.noEmptyParameter = The method annotated with @AfterBegin and @BeforeCompletion must take 0 arguments.
+2.ann.sessionsynchronization.noEmptyParameter = The method {1} annotated with {2} must take 0 arguments in bean class {0}.
+3.ann.sessionsynchronization.noEmptyParameter = The method {1} annotated with {2} must take 0 arguments in bean class {0}.
+
+1.ann.sessionSynchronization.invalidUse = Session synchronization annotations and configurations in deployment plan should not be used while SessionSynchronization interface is implemented by the bean class.
+2.ann.sessionSynchronization.invalidUse = Session synchronization annotations and configurations in deployment plan should not be used while SessionSynchronization interface is implemented by the bean class {0}.
+3.ann.sessionSynchronization.invalidUse = Session synchronization annotations and configurations in deployment plan should not be used while SessionSynchronization interface is implemented by the bean class {0}.
+
+1.ann.sessionSynchronization.methodNotFound = The session synchronization configuration in deployment plan refers to a non-method.
+2.ann.sessionSynchronization.methodNotFound = The method {1} configured for {2} in deployment plan is not found in bean class {0}. 
+3.ann.sessionSynchronization.methodNotFound = The method {1} configured for {2} in deployment plan is not found in bean class {0}.
+
+1.ann.sessionsynchronization.duplicatedAnnotatedMethod = Each stateful bean has at most one method for each of the three annotation types (@AfterBegin, @BeforeCompletion and @AfterCompletion).
+2.ann.sessionsynchronization.duplicatedAnnotatedMethod = The bean class {0} has more than one methods named {1} which are annotated with {2}.
+3.ann.sessionsynchronization.duplicatedAnnotatedMethod = The bean class {0} has more than one methods named {1} which are annotated with {2}.
+
 # fail(enterpriseBean.getEjbName(), "dependsOn.noSuchEjb", ejbName);
 1.dependsOn.noSuchEjb = Singleton @DependsOn refers to non-existant EJB:
 2.dependsOn.noSuchEjb = Singleton @DependsOn refers to non-existant EJB: {0}

Added: openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/StatefulSessionSynchronizationTest.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/StatefulSessionSynchronizationTest.java?rev=952895&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/StatefulSessionSynchronizationTest.java (added)
+++ openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/StatefulSessionSynchronizationTest.java Wed Jun  9 03:50:36 2010
@@ -0,0 +1,332 @@
+/**
+ *  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.stateful;
+
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.ejb.AfterBegin;
+import javax.ejb.AfterCompletion;
+import javax.ejb.BeforeCompletion;
+import javax.ejb.EJBException;
+import javax.ejb.Local;
+import javax.ejb.SessionSynchronization;
+import javax.ejb.Stateful;
+import javax.ejb.TransactionAttribute;
+import javax.ejb.TransactionAttributeType;
+import javax.interceptor.InvocationContext;
+import javax.naming.InitialContext;
+
+import junit.framework.TestCase;
+
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.assembler.classic.EjbJarInfo;
+import org.apache.openejb.assembler.classic.ProxyFactoryInfo;
+import org.apache.openejb.assembler.classic.SecurityServiceInfo;
+import org.apache.openejb.assembler.classic.TransactionServiceInfo;
+import org.apache.openejb.client.LocalInitialContextFactory;
+import org.apache.openejb.config.ConfigurationFactory;
+import org.apache.openejb.jee.AssemblyDescriptor;
+import org.apache.openejb.jee.EjbJar;
+import org.apache.openejb.jee.Interceptor;
+import org.apache.openejb.jee.InterceptorBinding;
+import org.apache.openejb.jee.NamedMethod;
+import org.apache.openejb.jee.StatefulBean;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class StatefulSessionSynchronizationTest extends TestCase {
+
+    private static final List<Call> result = new ArrayList<Call>();
+
+    public void test() throws Exception {
+        System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, LocalInitialContextFactory.class.getName());
+        Assembler assembler = new Assembler();
+        ConfigurationFactory config = new ConfigurationFactory();
+
+        assembler.createProxyFactory(config.configureService(ProxyFactoryInfo.class));
+        assembler.createTransactionManager(config.configureService(TransactionServiceInfo.class));
+        assembler.createSecurityService(config.configureService(SecurityServiceInfo.class));
+
+        EjbJar ejbJar = new EjbJar();
+        AssemblyDescriptor assemblyDescriptor = ejbJar.getAssemblyDescriptor();
+
+        Interceptor interceptor = new Interceptor(SimpleInterceptor.class);
+        ejbJar.addInterceptor(interceptor);
+
+        //Test SessionSynchronization interface
+        StatefulBean subBeanA = new StatefulBean(SubBeanA.class);
+        ejbJar.addEnterpriseBean(subBeanA);
+        assemblyDescriptor.addInterceptorBinding(new InterceptorBinding(subBeanA, interceptor));
+
+        //Test configure session synchronization callback methods in deployment plan
+        StatefulBean subBeanB = new StatefulBean(SubBeanB.class);
+        subBeanB.setAfterBeginMethod(new NamedMethod(SubBeanB.class.getDeclaredMethod("afterBegin")));
+        subBeanB.setBeforeCompletionMethod(new NamedMethod(SubBeanB.class.getDeclaredMethod("beforeCompletion")));
+        subBeanB.setAfterCompletionMethod(new NamedMethod(SubBeanB.class.getDeclaredMethod("afterCompletion", boolean.class)));
+        ejbJar.addEnterpriseBean(subBeanB);
+        assemblyDescriptor.addInterceptorBinding(new InterceptorBinding(subBeanB, interceptor));
+
+        //Test session synchronization methods via annotations
+        StatefulBean subBeanC = new StatefulBean(SubBeanC.class);
+        ejbJar.addEnterpriseBean(subBeanC);
+        assemblyDescriptor.addInterceptorBinding(new InterceptorBinding(subBeanC, interceptor));
+
+        //Test override the annotations by deployment plan
+        StatefulBean subBeanD = new StatefulBean(SubBeanD.class);
+        subBeanD.setAfterBeginMethod(new NamedMethod(SubBeanD.class.getDeclaredMethod("afterBeginNew")));
+        subBeanD.setBeforeCompletionMethod(new NamedMethod(SubBeanD.class.getDeclaredMethod("beforeCompletionNew")));
+        subBeanD.setAfterCompletionMethod(new NamedMethod(SubBeanD.class.getDeclaredMethod("afterCompletionNew", boolean.class)));
+        ejbJar.addEnterpriseBean(subBeanD);
+        assemblyDescriptor.addInterceptorBinding(new InterceptorBinding(subBeanD, interceptor));
+
+        //Test only one session synchronization method @AfterBegin
+        StatefulBean subBeanE = new StatefulBean(SubBeanE.class);
+        ejbJar.addEnterpriseBean(subBeanE);
+        assemblyDescriptor.addInterceptorBinding(new InterceptorBinding(subBeanE, interceptor));
+
+        //Test only one session synchronization method @AfterCompletion
+        StatefulBean subBeanF = new StatefulBean(SubBeanF.class);
+        ejbJar.addEnterpriseBean(subBeanF);
+        assemblyDescriptor.addInterceptorBinding(new InterceptorBinding(subBeanF, interceptor));
+
+        //Test only one session synchronization method @BeforeCompletion
+        StatefulBean subBeanG = new StatefulBean(SubBeanG.class);
+        ejbJar.addEnterpriseBean(subBeanG);
+        assemblyDescriptor.addInterceptorBinding(new InterceptorBinding(subBeanG, interceptor));
+
+        EjbJarInfo ejbJarInfo = config.configureApplication(ejbJar);
+        assembler.createApplication(ejbJarInfo);
+        InitialContext context = new InitialContext();
+
+        List<Call> expectedResult = Arrays.asList(Call.INTERCEPTOR_AFTER_BEGIN, Call.BEAN_AFTER_BEGIN, Call.INTERCEPTOR_BEFORE_COMPLETION, Call.BEAN_BEFORE_COMPLETION,
+                Call.INTERCEPTOR_AFTER_COMPLETION, Call.BEAN_AFTER_COMPLETION);
+
+        {
+            BeanInterface beanA = (BeanInterface) context.lookup("SubBeanALocal");
+            beanA.simpleMethod();
+            assertEquals(expectedResult, result);
+            result.clear();
+        }
+
+        {
+            BeanInterface beanB = (BeanInterface) context.lookup("SubBeanBLocal");
+            beanB.simpleMethod();
+            assertEquals(expectedResult, result);
+            result.clear();
+        }
+
+        {
+            BeanInterface beanC = (BeanInterface) context.lookup("SubBeanCLocal");
+            beanC.simpleMethod();
+            assertEquals(expectedResult, result);
+            result.clear();
+        }
+
+        {
+            BeanInterface beanD = (BeanInterface) context.lookup("SubBeanDLocal");
+            beanD.simpleMethod();
+            assertEquals(expectedResult, result);
+            result.clear();
+        }
+
+        {
+            BeanInterface beanE = (BeanInterface) context.lookup("SubBeanELocal");
+            beanE.simpleMethod();
+            assertEquals(Arrays.asList(Call.INTERCEPTOR_AFTER_BEGIN, Call.BEAN_AFTER_BEGIN, Call.INTERCEPTOR_BEFORE_COMPLETION, Call.INTERCEPTOR_AFTER_COMPLETION), result);
+            result.clear();
+        }
+
+        {
+            BeanInterface beanF = (BeanInterface) context.lookup("SubBeanFLocal");
+            beanF.simpleMethod();
+            assertEquals(Arrays.asList(Call.INTERCEPTOR_AFTER_BEGIN, Call.INTERCEPTOR_BEFORE_COMPLETION, Call.INTERCEPTOR_AFTER_COMPLETION, Call.BEAN_AFTER_COMPLETION), result);
+            result.clear();
+        }
+
+        {
+            BeanInterface beanG = (BeanInterface) context.lookup("SubBeanGLocal");
+            beanG.simpleMethod();
+            assertEquals(Arrays.asList(Call.INTERCEPTOR_AFTER_BEGIN, Call.INTERCEPTOR_BEFORE_COMPLETION, Call.BEAN_BEFORE_COMPLETION, Call.INTERCEPTOR_AFTER_COMPLETION), result);
+            result.clear();
+        }
+    }
+
+    public static interface BeanInterface {
+
+        public void simpleMethod();
+    }
+
+    public static class BaseBean implements BeanInterface {
+
+        @TransactionAttribute(TransactionAttributeType.REQUIRED)
+        public void simpleMethod() {
+
+        }
+
+    }
+
+    @Stateful
+    @Local(BeanInterface.class)
+    public static class SubBeanA extends BaseBean implements SessionSynchronization {
+
+        @Override
+        public void afterBegin() throws EJBException, RemoteException {
+            result.add(Call.BEAN_AFTER_BEGIN);
+        }
+
+        @Override
+        public void afterCompletion(boolean arg0) throws EJBException, RemoteException {
+            result.add(Call.BEAN_AFTER_COMPLETION);
+        }
+
+        @Override
+        public void beforeCompletion() throws EJBException, RemoteException {
+            result.add(Call.BEAN_BEFORE_COMPLETION);
+        }
+    }
+
+    @Stateful
+    @Local(BeanInterface.class)
+    public static class SubBeanB extends BaseBean {
+
+        public void afterBegin() throws EJBException, RemoteException {
+            result.add(Call.BEAN_AFTER_BEGIN);
+        }
+
+        public void afterCompletion(boolean arg0) throws EJBException, RemoteException {
+            result.add(Call.BEAN_AFTER_COMPLETION);
+        }
+
+        public void beforeCompletion() throws EJBException, RemoteException {
+            result.add(Call.BEAN_BEFORE_COMPLETION);
+        }
+
+    }
+
+    @Stateful
+    @Local(BeanInterface.class)
+    public static class SubBeanC extends BaseBean {
+
+        @AfterBegin
+        private void afterBegin() throws EJBException, RemoteException {
+            result.add(Call.BEAN_AFTER_BEGIN);
+        }
+
+        @AfterCompletion
+        protected void afterCompletion(boolean arg0) throws EJBException, RemoteException {
+            result.add(Call.BEAN_AFTER_COMPLETION);
+        }
+
+        @BeforeCompletion
+        public void beforeCompletion() throws EJBException, RemoteException {
+            result.add(Call.BEAN_BEFORE_COMPLETION);
+        }
+
+    }
+
+    @Stateful
+    @Local(BeanInterface.class)
+    public static class SubBeanD extends BaseBean {
+
+        @AfterBegin
+        public void afterBegin() throws EJBException, RemoteException {
+            result.add(Call.BAD_VALUE);
+        }
+
+        @AfterCompletion
+        public void afterCompletion(boolean arg0) throws EJBException, RemoteException {
+            result.add(Call.BAD_VALUE);
+        }
+
+        @BeforeCompletion
+        public void beforeCompletion() throws EJBException, RemoteException {
+            result.add(Call.BAD_VALUE);
+        }
+
+        private void afterBeginNew() throws EJBException, RemoteException {
+            result.add(Call.BEAN_AFTER_BEGIN);
+        }
+
+        protected void afterCompletionNew(boolean arg0) throws EJBException, RemoteException {
+            result.add(Call.BEAN_AFTER_COMPLETION);
+        }
+
+        public void beforeCompletionNew() throws EJBException, RemoteException {
+            result.add(Call.BEAN_BEFORE_COMPLETION);
+        }
+    }
+
+    @Stateful
+    @Local(BeanInterface.class)
+    public static class SubBeanE extends BaseBean {
+
+        @AfterBegin
+        public void afterBegin() throws EJBException, RemoteException {
+            result.add(Call.BEAN_AFTER_BEGIN);
+        }
+    }
+
+    @Stateful
+    @Local(BeanInterface.class)
+    public static class SubBeanF extends BaseBean {
+
+        @AfterCompletion
+        public void afterCompletion(boolean arg0) throws EJBException, RemoteException {
+            result.add(Call.BEAN_AFTER_COMPLETION);
+        }
+    }
+
+    @Stateful
+    @Local(BeanInterface.class)
+    public static class SubBeanG extends BaseBean {
+
+        @BeforeCompletion
+        public void beforeCompletion() throws EJBException, RemoteException {
+            result.add(Call.BEAN_BEFORE_COMPLETION);
+        }
+    }
+
+    public static class SimpleInterceptor {
+
+        @AfterBegin
+        public void afterBegin(InvocationContext invocationContext) throws Exception {
+            result.add(Call.INTERCEPTOR_AFTER_BEGIN);
+            invocationContext.proceed();
+        }
+
+        @BeforeCompletion
+        public void beforeComplete(InvocationContext invocationContext) throws Exception {
+            result.add(Call.INTERCEPTOR_BEFORE_COMPLETION);
+            invocationContext.proceed();
+        }
+
+        @AfterCompletion
+        public void afterComplete(InvocationContext invocationContext) throws Exception {
+            result.add(Call.INTERCEPTOR_AFTER_COMPLETION);
+            invocationContext.proceed();
+        }
+    }
+
+    public static enum Call {
+        BEAN_AFTER_BEGIN, BEAN_BEFORE_COMPLETION, BEAN_AFTER_COMPLETION, BAD_VALUE, INTERCEPTOR_AFTER_BEGIN, INTERCEPTOR_BEFORE_COMPLETION, INTERCEPTOR_AFTER_COMPLETION
+    }
+}

Propchange: openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/StatefulSessionSynchronizationTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/Interceptor.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/Interceptor.java?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/Interceptor.java (original)
+++ openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/Interceptor.java Wed Jun  9 03:50:36 2010
@@ -64,7 +64,10 @@ import java.util.Map;
         "postConstruct",
         "preDestroy",
         "postActivate",
-        "prePassivate"
+        "prePassivate",
+        "afterBegin",
+        "beforeCompletion",
+        "afterCompletion"
         })
 public class Interceptor implements JndiConsumer, Session {
 
@@ -100,6 +103,12 @@ public class Interceptor implements Jndi
     protected List<LifecycleCallback> postActivate;
     @XmlElement(name = "pre-passivate", required = true)
     protected List<LifecycleCallback> prePassivate;
+    @XmlElement(name = "after-begin", required = true)
+    protected List<LifecycleCallback> afterBegin;
+    @XmlElement(name = "before-completion", required = true)
+    protected List<LifecycleCallback> beforeCompletion;
+    @XmlElement(name = "after-completion", required = true)
+    protected List<LifecycleCallback> afterCompletion;
     @XmlAttribute
     @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
     @XmlID
@@ -324,6 +333,42 @@ public class Interceptor implements Jndi
         getPrePassivate().add(new LifecycleCallback(interceptorClass, method));
     }
 
+    public void addAfterBegin(String method) {
+        assert interceptorClass != null : "Set the interceptorClass before calling this method";
+        getAfterBegin().add(new LifecycleCallback(interceptorClass, method));
+    }
+
+    public void addAfterCompletion(String method) {
+        assert interceptorClass != null : "Set the interceptorClass before calling this method";
+        getAfterCompletion().add(new LifecycleCallback(interceptorClass, method));
+    }
+
+    public void addBeforeCompletion(String method) {
+        assert interceptorClass != null : "Set the interceptorClass before calling this method";
+        getBeforeCompletion().add(new LifecycleCallback(interceptorClass, method));
+    }
+
+    public List<LifecycleCallback> getAfterBegin() {
+        if (afterBegin == null) {
+            afterBegin = new ArrayList<LifecycleCallback>();
+        }
+        return this.afterBegin;
+    }
+
+    public List<LifecycleCallback> getAfterCompletion() {
+        if (afterCompletion == null) {
+            afterCompletion = new ArrayList<LifecycleCallback>();
+        }
+        return this.afterCompletion;
+    }
+
+    public List<LifecycleCallback> getBeforeCompletion() {
+        if (beforeCompletion == null) {
+            beforeCompletion = new ArrayList<LifecycleCallback>();
+        }
+        return this.beforeCompletion;
+    }
+
     public List<InitMethod> getInitMethod() {
         return new ArrayList<InitMethod>();
     }

Modified: openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/Session.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/Session.java?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/Session.java (original)
+++ openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/Session.java Wed Jun  9 03:50:36 2010
@@ -34,4 +34,15 @@ public interface Session extends Lifecyc
 
     List<RemoveMethod> getRemoveMethod();
 
+    List<LifecycleCallback> getAfterBegin();
+
+    void addAfterBegin(String method);
+
+    List<LifecycleCallback> getBeforeCompletion();
+
+    void addBeforeCompletion(String method);
+
+    List<LifecycleCallback> getAfterCompletion();
+
+    void addAfterCompletion(String method);
 }

Modified: openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/SessionBean.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/SessionBean.java?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/SessionBean.java (original)
+++ openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/SessionBean.java Wed Jun  9 03:50:36 2010
@@ -118,6 +118,9 @@ import javax.xml.bind.annotation.adapter
         "initMethod",
         "removeMethod",
         "transactionType",
+        "afterBeginMethod",
+        "beforeCompletionMethod",
+        "afterCompletionMethod",
         "concurrencyType",
         "aroundInvoke",
         "envEntry",
@@ -176,6 +179,12 @@ public class SessionBean implements Remo
     protected List<RemoveMethod> removeMethod;
     @XmlElement(name = "transaction-type")
     protected TransactionType transactionType;
+    @XmlElement(name = "after-begin-method")
+    protected NamedMethod afterBeginMethod;
+    @XmlElement(name = "before-completion-method")
+    protected NamedMethod beforeCompletionMethod;
+    @XmlElement(name = "after-completion-method")
+    protected NamedMethod afterCompletionMethod;
     @XmlElement(name = "concurrency-type")
     protected ConcurrencyType concurrencyType;
     @XmlElement(name = "around-invoke", required = true)
@@ -217,10 +226,10 @@ public class SessionBean implements Remo
     @XmlElementWrapper(name = "depends-on")
     @XmlElement(name = "ejb-name")
     protected List<String> dependsOn;
-    
+
     @XmlElement(name = "stateful-timeout", required = true)
     protected Timeout statefulTimeout;
-    
+
     @XmlElement(name = "access-timeout", required = true)
     protected Timeout accessTimeout;
 
@@ -229,6 +238,13 @@ public class SessionBean implements Remo
     @XmlID
     protected String id;
 
+    @XmlTransient
+    private List<LifecycleCallback> afterBegin;
+    @XmlTransient
+    private List<LifecycleCallback> beforeCompletion;
+    @XmlTransient
+    private List<LifecycleCallback> afterCompletion;
+
     public SessionBean() {
     }
 
@@ -479,6 +495,30 @@ public class SessionBean implements Remo
         this.concurrencyType = value;
     }
 
+    public NamedMethod getAfterBeginMethod() {
+        return afterBeginMethod;
+    }
+
+    public void setAfterBeginMethod(NamedMethod afterBeginMethod) {
+        this.afterBeginMethod = afterBeginMethod;
+    }
+
+    public NamedMethod getBeforeCompletionMethod() {
+        return beforeCompletionMethod;
+    }
+
+    public void setBeforeCompletionMethod(NamedMethod beforeCompletionMethod) {
+        this.beforeCompletionMethod = beforeCompletionMethod;
+    }
+
+    public NamedMethod getAfterCompletionMethod() {
+        return afterCompletionMethod;
+    }
+
+    public void setAfterCompletionMethod(NamedMethod afterCompletionMethod) {
+        this.afterCompletionMethod = afterCompletionMethod;
+    }
+
     public List<AroundInvoke> getAroundInvoke() {
         if (aroundInvoke == null) {
             aroundInvoke = new ArrayList<AroundInvoke>();
@@ -729,4 +769,39 @@ public class SessionBean implements Remo
 		this.accessTimeout = accessTimeout;
 	}
 
+	public void addAfterBegin(String method) {
+        assert ejbClass != null : "Set the interceptorClass before calling this method";
+        getAfterBegin().add(new LifecycleCallback(ejbClass, method));
+    }
+
+    public void addAfterCompletion(String method) {
+        assert ejbClass != null : "Set the interceptorClass before calling this method";
+        getAfterCompletion().add(new LifecycleCallback(ejbClass, method));
+    }
+
+    public void addBeforeCompletion(String method) {
+        assert ejbClass != null : "Set the interceptorClass before calling this method";
+        getBeforeCompletion().add(new LifecycleCallback(ejbClass, method));
+    }
+
+    public List<LifecycleCallback> getAfterBegin() {
+        if (afterBegin == null) {
+            afterBegin = new ArrayList<LifecycleCallback>();
+        }
+        return afterBegin;
+    }
+
+    public List<LifecycleCallback> getAfterCompletion() {
+        if (afterCompletion == null) {
+            afterCompletion = new ArrayList<LifecycleCallback>();
+        }
+        return this.afterCompletion;
+    }
+
+    public List<LifecycleCallback> getBeforeCompletion() {
+        if (beforeCompletion == null) {
+            beforeCompletion = new ArrayList<LifecycleCallback>();
+        }
+        return this.beforeCompletion;
+    }
 }

Modified: openejb/trunk/openejb3/container/openejb-jee/src/test/java/org/apache/openejb/jee/JeeTest.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-jee/src/test/java/org/apache/openejb/jee/JeeTest.java?rev=952895&r1=952894&r2=952895&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-jee/src/test/java/org/apache/openejb/jee/JeeTest.java (original)
+++ openejb/trunk/openejb3/container/openejb-jee/src/test/java/org/apache/openejb/jee/JeeTest.java Wed Jun  9 03:50:36 2010
@@ -104,6 +104,27 @@ public class JeeTest extends TestCase {
 		assertNotNull("Unable to get the StatefulTimeout value", sbean.getStatefulTimeout());
     }
 
+    public void testSessionSynchronization() throws Exception {
+        String fileName = "ejb-session-synchronization.xml";
+        InputStream in = this.getClass().getClassLoader().getResourceAsStream(fileName);
+
+        Object o = JaxbJavaee.unmarshal(EjbJar.class, in);
+
+        EjbJar ejbJar = (EjbJar) o;
+        EnterpriseBean bean = ejbJar.getEnterpriseBean("TestBean");
+
+        assertTrue("The bean TestBean  is not a SessionBean", bean instanceof SessionBean);
+        SessionBean sbean = (SessionBean) bean;
+
+        assertNotNull("Unable to get the afterBegin value", sbean.getAfterBeginMethod());
+        assertNotNull("Unable to get the beforeCompletion value", sbean.getBeforeCompletionMethod());
+        assertNotNull("Unable to get the afterCompletion value", sbean.getAfterCompletionMethod());
+
+        assertNotNull("Unable to get the afterBegin value", sbean.getAfterBegin());
+        assertNotNull("Unable to get the beforeCompletion value", sbean.getBeforeCompletion());
+        assertNotNull("Unable to get the afterCompletion value", sbean.getAfterCompletion());
+    }
+
     public void testEjbJarMdb20() throws Exception {
         String fileName = "ejb-jar-mdb-2.0.xml";
         InputStream in = this.getClass().getClassLoader().getResourceAsStream(fileName);

Added: openejb/trunk/openejb3/container/openejb-jee/src/test/resources/ejb-session-synchronization.xml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-jee/src/test/resources/ejb-session-synchronization.xml?rev=952895&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-jee/src/test/resources/ejb-session-synchronization.xml (added)
+++ openejb/trunk/openejb3/container/openejb-jee/src/test/resources/ejb-session-synchronization.xml Wed Jun  9 03:50:36 2010
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+
+    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.
+-->
+
+<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" version="3.1" metadata-complete="true">
+    <enterprise-beans>
+        <session>
+            <description>String</description>
+            <ejb-name>TestBean</ejb-name>
+            <after-begin-method>
+                <method-name>afterBegin</method-name>
+            </after-begin-method>      
+            <before-completion-method>
+                <method-name>beforeCompletion</method-name>
+            </before-completion-method>
+            <after-completion-method>
+                <method-name>afterCompletion</method-name>
+                <method-params>
+                    <method-param>boolean</method-param>
+                </method-params>
+            </after-completion-method>                  
+        </session>
+    </enterprise-beans>
+</ejb-jar>

Propchange: openejb/trunk/openejb3/container/openejb-jee/src/test/resources/ejb-session-synchronization.xml
------------------------------------------------------------------------------
    svn:eol-style = native