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