3 Replies Latest reply on Oct 12, 2009 1:27 PM by Debasish Ray Chawdhuri

    Multiple default PostConstruct method not called

    Debasish Ray Chawdhuri Newbie

      I think I have encountered a strange behaviour

      The specification EJB3.0 clearly says that it is possible to have multiple default interceptors can be specified and all of them can have @PostConstruct. The order of the invocation would be the same as in the deployment descriptor. However, in JBoss, only the first one is called and the rest are ignored. It is completely repeatable

      I'm using JBoss Version 5.0.1.GA (build: SVNTag=JBoss_5_0_1_GA date=200902232048)

      The following is my ejb-jar.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <ejb-jar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:ejb="http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd" version="3.0">
       <display-name>DemoEJB </display-name>
       <enterprise-beans>
       <session>
       <ejb-name>DemoFirstEJB</ejb-name>
       <business-local>com.ejb.demo.DemoFirstEJBLocal</business-local>
       <timeout-method>
       <method-name>timeout</method-name>
       </timeout-method>
       <transaction-type>Container</transaction-type>
      
       <message-destination-ref>
       <message-destination-ref-name>demoDestination</message-destination-ref-name>
       <message-destination-link>demoDestination</message-destination-link>
       <injection-target>
       <injection-target-class>com.ejb.demo.DemoFirstEJB</injection-target-class>
       <injection-target-name>topic</injection-target-name>
       </injection-target>
      
       </message-destination-ref>
      
       </session>
       <message-driven>
       <ejb-name>DemoMDB</ejb-name>
       <message-destination-link>demoDestination</message-destination-link>
       <activation-config>
       <activation-config-property>
       <activation-config-property-name>destination</activation-config-property-name>
       <activation-config-property-value>/topic/testTopic</activation-config-property-value>
       </activation-config-property>
       </activation-config>
      
       </message-driven>
       </enterprise-beans>
       <interceptors>
       <description>Timout Interceptor</description>
       <interceptor>
       <interceptor-class>com.ejb.demo.interceptors.DemoInterceptor</interceptor-class>
      
       <post-construct>
       <lifecycle-callback-method>postConstruct</lifecycle-callback-method>
       </post-construct>
      
       </interceptor>
       <interceptor>
       <interceptor-class>org.javaeeutils.logger.interceptors.LoggingInterceptor</interceptor-class>
       </interceptor>
       </interceptors>
       <assembly-descriptor>
       <container-transaction>
      
       <method>
       <ejb-name>DemoFirstEJB</ejb-name>
       <method-name>*</method-name>
       </method>
       <trans-attribute>Required</trans-attribute>
       </container-transaction>
      
       <interceptor-binding>
       <ejb-name>*</ejb-name>
      
       <interceptor-class>org.javaeeutils.logger.interceptors.LoggingInterceptor</interceptor-class>
       <interceptor-class>com.ejb.demo.interceptors.DemoInterceptor</interceptor-class>
       </interceptor-binding>
      
      
       <message-destination>
       <message-destination-name>demoDestination</message-destination-name>
       <mapped-name>/topic/testTopic</mapped-name>
       </message-destination>
      
       </assembly-descriptor>
      
      </ejb-jar>
      



        • 1. Re: Multiple default PostConstruct method not called
          jaikiran pai Master

          Looking at the code you attached to the JIRA https://jira.jboss.org/jira/browse/EJBTHREE-1937 this appears to be a bug in your application code.

          Your interceptors do not call the invocationContext.proceed in the post construct operations. As per section 12.5 of EJB3 spec:

          "EJB3 Spec, Section 12.5" wrote:
          Interceptor methods must always call InvocationContext.proceed() or no subsequent interceptor methods or bean business method or lifecycle callback methods will be invoked.




          • 2. Re: Multiple default PostConstruct method not called
            Debasish Ray Chawdhuri Newbie

            I was not calling ictx.proceed from PostConstruct (It should have thrown exception anyway). I had aroundInvoke also in those incerceptors (The spec says you can do that 12.4 "Lifecycle callback interceptor methods and business method interceptor methods may be defined on the same interceptor class."). Now lets try a simpler test case: [Since I cannot attach the jar here, I will write the whole code]

            The bean class

            package com.ejb.demo;
            
            import java.util.Date;
            
            import javax.annotation.Resource;
            import javax.ejb.SessionContext;
            import javax.ejb.Stateless;
            import javax.ejb.Timer;
            import javax.ejb.TimerService;
            import javax.ejb.TransactionAttribute;
            import javax.ejb.TransactionAttributeType;
            import javax.jms.Connection;
            import javax.jms.JMSException;
            import javax.jms.MessageProducer;
            import javax.jms.Session;
            import javax.jms.TextMessage;
            import javax.jms.Topic;
            import javax.jms.TopicConnectionFactory;
            
            import org.javaeeutils.logger.annotation.Logger;
            import org.springframework.beans.factory.annotation.Configurable;
            import org.springframework.context.ApplicationContext;
            import org.springframework.context.support.ClassPathXmlApplicationContext;
            
            /**
             * Session Bean implementation class DemoFirstEJB
             */
            @Stateless
            
            public class DemoFirstEJB implements DemoFirstEJBRemote, DemoFirstEJBLocal {
            
             /**
             * Default constructor.
             */
             @Resource
             private SessionContext ctx;
            
            
             @Resource
             private TimerService timerService;
            
             public DemoFirstEJB() {
             // TODO Auto-generated constructor stub
             }
            
             @Override
             @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
             public void setTimer() {
            
            
             System.out.println("Inside setTimer");
            
             }
            
            
            }
            


            The bean interface
            
            package com.ejb.demo;
            import javax.ejb.Remote;
            
            @Remote
            public interface DemoFirstEJBRemote {
             public void setTimer();
            }
            
            


            The First Interceptor
            package com.ejb.demo.interceptors;
            
            import javax.annotation.PostConstruct;
            import javax.interceptor.AroundInvoke;
            import javax.interceptor.InvocationContext;
            
            
            
            public class DemoInterceptor {
            
             @AroundInvoke
             public Object aroundTimeout(InvocationContext ictx) throws Exception{
             System.out.println("Interceptor 1: AroundInvoke");
             return ictx.proceed();
             }
             @PostConstruct
             public void postConstruct(InvocationContext ictx){
             System.out.println("Interceptor 1: PostConstruct");
             }
            }
            


            The second Interceptor
            
            package com.ejb.demo.interceptors;
            
            import javax.annotation.PostConstruct;
            import javax.ejb.Timer;
            import javax.interceptor.AroundInvoke;
            import javax.interceptor.InvocationContext;
            
            public class DemoInterceptor2 {
             @AroundInvoke
             public Object aroundTimeout(InvocationContext ictx) throws Exception{
             System.out.println("Interceptor 2: AroundInvoke");
             return ictx.proceed();
             }
             @PostConstruct
             public void postConstruct(InvocationContext ictx){
             System.out.println("Interceptor 2: PostConstruct");
             }
            }
            
            


            The deployment descriptor
            <?xml version="1.0" encoding="UTF-8"?>
            <ejb-jar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:ejb="http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd" version="3.0">
             <display-name>DemoEJB </display-name>
             <enterprise-beans>
             <session>
             <ejb-name>DemoFirstEJB</ejb-name>
             <business-local>com.ejb.demo.DemoFirstEJBLocal</business-local>
             <transaction-type>Container</transaction-type>
            
            
            
             </session>
            
             </enterprise-beans>
            
             <assembly-descriptor>
             <container-transaction>
            
             <method>
             <ejb-name>DemoFirstEJB</ejb-name>
             <method-name>*</method-name>
             </method>
             <trans-attribute>Required</trans-attribute>
             </container-transaction>
            
             <interceptor-binding>
             <ejb-name>*</ejb-name>
            
             <interceptor-class>com.ejb.demo.interceptors.DemoInterceptor2</interceptor-class>
             <interceptor-class>com.ejb.demo.interceptors.DemoInterceptor</interceptor-class>
             </interceptor-binding>
            
            
            
             </assembly-descriptor>
            
            </ejb-jar>
            


            The remote client (stand alone java application]
            package com.demo.ejb.test;
            
            import java.util.Properties;
            
            import javax.naming.InitialContext;
            import javax.naming.NamingException;
            import javax.rmi.PortableRemoteObject;
            
            import com.ejb.demo.DemoFirstEJBRemote;
            
            public class Main {
            
             /**
             * @param args
             * @throws NamingException
             */
             public static void main(String[] args) throws NamingException {
             Properties p = new Properties();
             p.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
             p.put("java.naming.provider.url", "jnp://localhost:1099");
             p.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
            
            
             InitialContext ctx = new InitialContext(p);
             Object rem=ctx.lookup("DemoFirstEJB/remote");
             DemoFirstEJBRemote remote=(DemoFirstEJBRemote) PortableRemoteObject.narrow(rem, DemoFirstEJBRemote.class);
             remote.setTimer();
            
             }
            
            }
            


            And here is the output of JBoss console when we run the client

            
            22:24:45,610 INFO [STDOUT] Interceptor 2: PostConstruct
            22:24:45,611 WARN [InterceptorsFactory] EJBTHREE-1246: Do not use InterceptorsFactory with a ManagedObjectAdvisor, InterceptorRegistry should be used via the bean container
            22:24:45,611 WARN [InterceptorsFactory] EJBTHREE-1246: Do not use InterceptorsFactory with a ManagedObjectAdvisor, InterceptorRegistry should be used via the bean container
            22:24:45,612 INFO [STDOUT] Interceptor 2: AroundInvoke
            22:24:45,612 INFO [STDOUT] Interceptor 1: AroundInvoke
            22:24:45,613 INFO [STDOUT] Inside setTimer
            
            


            Thus only the PostConstruct of Interceptor2 is called


            Now if I change the interceptor-binding to the following

            <interceptor-binding>
             <ejb-name>*</ejb-name>
             <interceptor-class>com.ejb.demo.interceptors.DemoInterceptor</interceptor-class>
             <interceptor-class>com.ejb.demo.interceptors.DemoInterceptor2</interceptor-class>
             </interceptor-binding>
            


            Here is the output
            22:46:44,446 INFO [STDOUT] Interceptor 1: PostConstruct
            22:46:44,447 WARN [InterceptorsFactory] EJBTHREE-1246: Do not use InterceptorsFactory with a ManagedObjectAdvisor, InterceptorRegistry should be used via the bean container
            22:46:44,447 WARN [InterceptorsFactory] EJBTHREE-1246: Do not use InterceptorsFactory with a ManagedObjectAdvisor, InterceptorRegistry should be used via the bean container
            22:46:44,448 INFO [STDOUT] Interceptor 1: AroundInvoke
            22:46:44,449 INFO [STDOUT] Interceptor 2: AroundInvoke
            22:46:44,449 INFO [STDOUT] Inside setTimer
            


            Thus only the PostConstruct of Inceptor1 is only called


            Thus we can see only the first in the list of interceptors is called

            • 3. Re: Multiple default PostConstruct method not called
              Debasish Ray Chawdhuri Newbie

              OK thanks, I got it. But the same 'WRONG' program seems to work in Glassfish!. I now think they are the ones violating the spec. Thanks for your time and effort and sorry for the inconveniences I caused.