The EJB 3.0 specification defines some callbacks, and allows you to handle these by implementing your own callback handlers. The callbacks defined for each bean are shown below:
The callbacks are not compulsory, and you can define the ones you want to handle.
@javax.persistence.EntityListener("org.jboss.tutorial.callback.bean.CustomerCallbackListener")This specifies that the org.jboss.tutorial.callback.bean.CustomerCallbackListener class should be used as the callback listener class for the bean. Now open CustomerCallbackListener and you will see that the class annotates the callback methods in the same way as when defining callbacks on the bean class itself. However, one important difference is that callback methods defined in a listener class must take a single argument, which will be the bean we are working with. The parameter must be of type java.lang.Object, or the actual bean type.
Object <any method name>(InvocationContext)
CustomerDAOBean specifies that it wants to use an external interceptor.
@Stateless @Remote(CustomerDAO.class) @Interceptors({LifecycleInterceptor.class}) public class CustomerDAOBean implements CustomerDAO { ... }
and LifecycleInterceptor has a @PostConstruct annotated method. As shown, each interceptor lifecycle method must call proceed on the InvocationContext to invoke the next interceptor.
Interceptors may contain both the @AroundInvoke methods for intercepting business methods, and lifecycle methods. If you want to configure lifecycle methods for your interceptors with xml, you will need to do this in the interceptor section of ejb-jar.xml, and the keywords are post-construct-method, post-activate-method, pre-passivate-method and pre-destry-method. For example
<ejb-jar> <interceptors> <interceptor> <interceptor-class>org.acme.SomeInterceptor</interceptor-class> <around-invoke-method> <method-name>interceptorMethod</method-name> </around-invoke-method> <post-construct-method> <method-name>sendCancelMessage</method-name> </post-construct-method> <pre-destroy-method> <method-name>sendCancelMessage</method-name> </pre-destroy-method> </interceptor> </interceptors> </ejb-jar>
Interceptor methods for handling lifecycle events follow exactly the same ordering and inheritance rules as business method interceptor methods, and an interceptor instance follows the lifecycle of the bean instance it is bound to.
Unix: $ export JBOSS_HOME=<where your jboss 4.0 distribution is> Windows: $ set JBOSS_HOME=<where your jboss 4.0 distribution is> $ ant $ ant run run: [java] Create Bill Burke and Monica Smith [java] log4j:WARN No appenders could be found for logger (org.jboss.remoting.Client). [java] log4j:WARN Please initialize the log4j system properly. [java] Bill and Monica get married [java] Get all the Burkes [java] There are now 2 Burkes [java] Bill and Monica are moving abroad
In the jboss console window you should see:
20:06:05,596 INFO [STDOUT] LifecycleInterceptor postConstruct 20:06:05,596 INFO [STDOUT] PostConstruct - Have EntityManager: true 20:06:05,596 INFO [STDOUT] -- CustomerDAOBean.create() 20:06:05,596 INFO [STDOUT] doPrePersist: About to create Customer: Bill Burke 20:06:05,596 INFO [STDOUT] doPostPersist: Created Customer: Bill Burke 20:06:05,617 INFO [STDOUT] -- CustomerDAOBean.create() 20:06:05,617 INFO [STDOUT] doPrePersist: About to create Customer: Monica Smith 20:06:05,617 INFO [STDOUT] doPostPersist: Created Customer: Monica Smith 20:06:05,617 INFO [STDOUT] -- CustomerDAOBean.find() 20:06:05,627 INFO [STDOUT] doPostLoad: Loaded Customer: Monica Smith 20:06:05,627 INFO [STDOUT] -- CustomerDAOBean.merge() 20:06:05,637 INFO [STDOUT] doPostLoad: Loaded Customer: Monica Smith 20:06:05,637 INFO [STDOUT] doPreUpdate: About to update Customer: Monica Burke 20:06:05,657 INFO [STDOUT] doPostUpdate: Updated Customer: Monica Burke 20:06:05,667 INFO [STDOUT] -- CustomerDAOBean.findByLastName(id) 20:06:05,677 INFO [STDOUT] doPostLoad: Loaded Customer: Bill Burke 20:06:05,677 INFO [STDOUT] doPostLoad: Loaded Customer: Monica Burke 20:06:05,687 INFO [STDOUT] -- CustomerDAOBean.delete() 20:06:05,687 INFO [STDOUT] doPreRemove: About to delete Customer: Bill Burke 20:06:05,687 INFO [STDOUT] doPreRemove: About to delete Customer: Monica Burke 20:06:05,687 INFO [STDOUT] doPostRemove: Deleted Customer: Bill Burke 20:06:05,697 INFO [STDOUT] doPostRemove: Deleted Customer: Monica Burke
Now if you open up JBOSS_HOME/server/all/deploy/ejb3.deployer/META-INF/hibernate.properties and add the following line
hibernate.show_sql=true
and restart JBoss before running the example again, the output should be:
20:22:10,013 INFO [STDOUT] PostConstruct - Have EntityManager: true 20:22:10,033 INFO [STDOUT] -- CustomerDAOBean.create() 20:22:10,103 INFO [STDOUT] doPrePersist: About to create Customer: Bill Burke 20:22:10,123 INFO [STDOUT] Hibernate: insert into CUSTOMER (STATE, FIRST, LAST, STREET, CITY, ZIP, id) values (?, ?, ?, ?, ?, ?, null) 20:22:10,133 INFO [STDOUT] Hibernate: call identity() 20:22:10,143 INFO [STDOUT] doPostPersist: Created Customer: Bill Burke 20:22:10,194 INFO [STDOUT] -- CustomerDAOBean.create() 20:22:10,194 INFO [STDOUT] doPrePersist: About to create Customer: Monica Smith 20:22:10,194 INFO [STDOUT] Hibernate: insert into CUSTOMER (STATE, FIRST, LAST, STREET, CITY, ZIP, id) values (?, ?, ?, ?, ?, ?, null) 20:22:10,194 INFO [STDOUT] Hibernate: call identity() 20:22:10,194 INFO [STDOUT] doPostPersist: Created Customer: Monica Smith 20:22:10,264 INFO [STDOUT] -- CustomerDAOBean.find() 20:22:10,274 INFO [STDOUT] Hibernate: select customer0_.id as id0_, customer0_.STATE as STATE0_0_, customer0_.FIRST as FIRST0_0_, customer0_.LAST as LAST0_0_, customer0_.STREET as STREET0_0_, customer0_.CITY as CITY0_0_, customer0_.ZIP as ZIP0_0_ from CUSTOMER customer0_ where customer0_.id=? 20:22:10,284 INFO [STDOUT] doPostLoad: Loaded Customer: Monica Smith 20:22:10,294 INFO [STDOUT] -- CustomerDAOBean.merge() 20:22:10,304 INFO [STDOUT] Hibernate: select customer0_.id as id0_, customer0_.STATE as STATE0_0_, customer0_.FIRST as FIRST0_0_, customer0_.LAST as LAST0_0_, customer0_.STREET as STREET0_0_, customer0_.CITY as CITY0_0_, customer0_.ZIP as ZIP0_0_ from CUSTOMER customer0_ where customer0_.id=? 20:22:10,304 INFO [STDOUT] doPostLoad: Loaded Customer: Monica Smith 20:22:10,304 INFO [STDOUT] doPreUpdate: About to update Customer: Monica Burke 20:22:10,314 INFO [STDOUT] Hibernate: update CUSTOMER set STATE=?, FIRST=?, LAST=?, STREET=?, CITY=?, ZIP=? where id=? 20:22:10,314 INFO [STDOUT] doPostUpdate: Updated Customer: Monica Burke 20:22:10,324 INFO [STDOUT] -- CustomerDAOBean.findByLastName(id) 20:22:10,604 INFO [STDOUT] Hibernate: select customer0_.id as id, customer0_.STATE as STATE0_, customer0_.FIRST as FIRST0_, customer0_.LAST as LAST0_ , customer0_.STREET as STREET0_, customer0_.CITY as CITY0_, customer0_.ZIP as ZIP0_ from CUSTOMER customer0_ where (customer0_.LAST=? ) 20:22:10,604 INFO [STDOUT] doPostLoad: Loaded Customer: Bill Burke 20:22:10,604 INFO [STDOUT] doPostLoad: Loaded Customer: Monica Burke 20:22:10,624 INFO [STDOUT] -- CustomerDAOBean.delete() 20:22:10,634 INFO [STDOUT] doPreRemove: About to delete Customer: Bill Burke 20:22:10,644 INFO [STDOUT] doPreRemove: About to delete Customer: Monica Burke 20:22:10,644 INFO [STDOUT] Hibernate: delete from CUSTOMER where id=? 20:22:10,644 INFO [STDOUT] doPostRemove: Deleted Customer: Bill Burke 20:22:10,644 INFO [STDOUT] Hibernate: delete from CUSTOMER where id=? 20:22:10,644 INFO [STDOUT] doPostRemove: Deleted Customer: Monica Burke
Thus you can see how the callbacks on the entity bean wrap the interaction with the database.