Run-time lookup for EJBs in MDB consuming immediately after deploy
Asked Answered
H

4

11

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'
    }
}
Hypsometer answered 18/2, 2013 at 11:31 Comment(5)
Quick idea: If you have transactionalized the consumption, you could perhaps reject the tx on NameNotFoundException's, have a sensible retry-policy and hope the EJBs has deployed next time?Esau
It's something, but notice that if I'll have milions of messages waiting in queues (that's my case actually), every one will be initially processed to just reject tx. The database will probably kneel. It anyway gets a huge load on application startup.Expulsive
Can you paste a snippet of code here .. how are performing lookup . whats your MDB class definition ?Marquettamarquette
can you just not persist the messages in queue, so that after deploy the queue would be empty? given your case, I don't understand why you're persisting such messages.Jerold
Unfortunately, I have to. It's kind of financial processing, we really have to persist all messages (and even replicate them but that's another story).Expulsive
D
4

Use one of these four different approaches.

  1. 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;
    }
    

    }

  2. 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>
    
  3. 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.

  4. 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?

Dibucaine answered 22/2, 2013 at 15:58 Comment(1)
Glen, thanks for the answer. That confirms that there's no any strict and elegant solution using these technologies. Kind of hacking is needed anyway. I'll probably try with 3 or 4 option.Expulsive
D
2

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.

Deranged answered 22/2, 2013 at 7:53 Comment(0)
X
1

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?"

Xerography answered 23/2, 2013 at 2:42 Comment(0)
P
1

you could implement a loop with backoff around the lookup call.

Pseudonym answered 23/2, 2013 at 3:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.