I have Java EE 5 project using JBoss 5.1 and problem like this. I have to do kind of run-time lookup for some EJBs in MDBs using a string that results from message content. It's just kind of service locator pattern used in MDBs. Now, since MDBs start consuming just after deploy, I have a lot NameNotFoundException
since implicit deployment order doesn't work well here (run-time lookup). What do you think about it? Is it possible to do it really well using EJB 3.0? It's also acceptable for me to use any vendor-specific stuff (JBoss 5.1) if it resolves the problem.
Some code snippet to visualize the situation:
@MessageDriven(mappedName="jms/Queue")
public class MessageBean implements MessageListener {
@Resource
private MessageDrivenContext mdc;
public void onMessage(Message msg) {
final String beanName = // extract somehow the bean's name from 'msg'
final Context ctx = new InitialContext();
final Object obj = ctx.lookup(beanName); // NameNotFoundException
// do something with 'obj'
}
}
Use one of these four different approaches.
Declare EJB dependencies (EJB references) using "@EJB" annotation (don't use JNDI lookup). For entity bean references, must refer to the entity bean home interface. Container must ensure all dependencies are injected before methods/message-listeners are processed:
MessageDriven(mappedName="jms/Queue")
public class MessageBean implements MessageListener {
@EJB private EntityBeanHomeA entityBeanHomeA;
@EJB private EntityBeanHomeB entityBeanHomeB;
@EJB private EntityBeanHomeC entityBeanHomeC;
@EJB private SessionBeanD sessionBeanD;
@Resource
private MessageDrivenContext mdc;
public void onMessage(Message msg) {
final String beanName = // extract somehow the bean's name from 'msg'
final Object obj = getDependentEJB(beanName);
// do something with 'obj'
}
private Object getDependentEJB(String beanName) {
Object result = null;
if ("EntityBeanHomeA".equals(beanName)) {
result = entityBeanHomeA;
else if ("EntityBeanHomeB".equals(beanName)) {
result = entityBeanHomeB;
else ("EntityBeanHomeC".equals(beanName)) {
result = entityBeanHomeC;
else ("SessionBeanD".equals(beanName)) {
result = sessionBeanD;
}
return result;
}
}
Use JNDI lookup, but declare EJB dependencies via EJB deployment descriptors. Again, the container must ensure ensure all dependencies are setup before methods/messages are processed:
@MessageDriven(mappedName="jms/Queue") public class MessageBean implements MessageListener {
// as given in the original Question...
}
Deployment descriptor:
<enterprise-beans>
<message-driven>
...
<ejb-name>MessageBean</ejb-name>
<ejb-class>com.company.pkg.MessageBean</ejb-class>
<messaging-type>javax.jms.MessageListener</messaging-type>
<message-destination-type>javax.jms.Queue</message-destination-type>
<message-destination-link>ExpenseProcessingQueue</message-destination-link>
<ejb-ref>
<description> This is a reference to an EJB 2.1 entity bean
that encapsulates access to employee records.
</description>
<ejb-ref-name>ejb/EmplRecord</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<home>com.wombat.empl.EmployeeRecordHome</home>
<remote>com.wombat.empl.EmployeeRecord</remote>
<ejb-link>EmployeeRecord</ejb-link> <-- if in same EJB jar -->
<-- ../emp/emp.jar#EmployeeRecord if in diff EJB jar -->
</ejb-ref>
<ejb-local-ref>
<description> This is a reference to the local business interface
of an EJB 3.0 session bean that provides a payroll service.
</description>
<ejb-ref-name>ejb/Payroll</ejb-ref-name>
<local>com.aardvark.payroll.Payroll</local>
<ejb-link>Payroll</ejb-link>
</ejb-local-ref>
<ejb-local-ref>
<description> This is a reference to the local business interface of an
EJB 3.0 session bean that provides a pension plan service.
</description>
<ejb-ref-name>ejb/PensionPlan</ejb-ref-name>
<local>com.wombat.empl.PensionPlan</local>
<ejb-link>PensionPlan</ejb-link> <-- if in same EJB jar -->
</ejb-local-ref>
...
</message-driven>
...
</enterprise-beans>
Use JNDI lookup but do not declare dependencies using either @EJB annotations or EJB deployment - handle entirely with your own logic, without the container helping. Use delays/error handling.
Use JBoss proprietary configuration to control deployment order:
http://texnoblog.wordpress.com/2010/09/16/depends-in-jboss/
How to order deployment of EJBs and JMS queue config in JBoss 5?
One way would be to create a dummy-ejb that you inject into your MDB, this way your mdb would not start consuming until that injection can actually take place.
If the dummy-ejb is bundled with the EJBs you intended to do dynamic lookup on, this should work
My answer here solves a similiar use-case.
I think that the best approach would be to delay the deployment of your MDB until all your EJBs are up & running. This is basically approach number 4 in the answer above.
"Use JBoss proprietary configuration to control deployment order:
http://texnoblog.wordpress.com/2010/09/16/depends-in-jboss/
How to order deployment of EJBs and JMS queue config in JBoss 5?"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With