1
votes

Since a message driven bean is a type of EJB, I would expect that I would be able to inject one into another, but I am having issues. I have to MDBs and need to inject one into the other something like this:

@MessageDriven(mappedName = "jms/QueueOne")
public class MessageBeanOne
{
    @EJB
    private EntityService service;

    @EJB
    private MessageBeanTwo mdbTwo;

    public void onMessage(Message message)
    {
        log.info("Received message from jms/QueueOne: " + message);
        String entityId= null;

        try
        {
            if (message instanceof TextMessage)
            {
                entityId = ((TextMessage) message).getText();
            }
            else
            {
                // error handling
            }
        }
        catch (Exception ex)
        {
           // error handling
        }

        Entity myEntity = service.getEntity(entityId);
        mdbTwo.process(myEntity);
    }
}


@MessageDriven(mappedName = "jms/TopicOne")
public class MessageBeanTwo
{
    @EJB
    private EntityService service;

    private boolean goodToProcess = true;

    public void process(Entity entity)
    {
        while(goodToProcess)
        {
            // process entity using injected service object
        }
    }

    public void onMessage(Message message)
    {
        log.info("Received message from jms/TopicOne: " + message);
        String status = null;

        try
        {
            if (message instanceof TextMessage)
            {
                status = ((TextMessage) message).getText();
            }
            else
            {
                // error handling
            }
        }
        catch (Exception ex)
        {
           // error handling
        }

        if (status.equals("cancel")
        {
            goodToProcess = false;
        }
    }
}

They are deployed as an ear into Glassfish 3.1.1. and I get this error message in my server.log:

[#|2011-11-23T10:55:35.546-0700|SEVERE|glassfish3.1.1|javax.enterprise.system.container.ejb.mdb.com.sun.ejb.containers|_ThreadID=19;_ThreadName=Thread-2;|MDB00050: Message-driven bean [MyApp-ear-1.0:MessageBeanOne]: Exception in creating message-driven ejb : [com.sun.enterprise.container.common.spi.util.InjectionException: Exception attempting to inject Remote ejb-ref name=my.package.MessageBeanOne/messageBeanTwo,Remote 3.x interface =my.package.MessageBeanTwo,ejb-link=null,lookup=,mappedName=,jndi-name=my.package.MessageBeanTwo,refType=Session into class my.package.MessageBeanOne: Lookup failed for 'java:comp/env/my.package.MessageBeanOne/messageBeanTwo' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming}]|#]
[#|2011-11-23T10:55:35.547-0700|SEVERE|glassfish3.1.1|javax.enterprise.system.container.ejb.mdb.com.sun.ejb.containers|_ThreadID=19;_ThreadName=Thread-2;|com.sun.enterprise.container.common.spi.util.InjectionException com.sun.enterprise.container.common.spi.util.InjectionException: Exception attempting to inject Remote ejb-ref name=my.package.MessageBeanOne/messageBeanTwo,Remote 3.x interface =my.package.MessageBeanTwo,ejb-link=null,lookup=,mappedName=,jndi-name=my.package.MessageBeanTwo,refType=Session into class my.package.MessageBeanOne: Lookup failed for 'java:comp/env/my.package.MessageBeanOne/messageBeanTwo' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming}
        at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl._inject(InjectionManagerImpl.java:703)
        at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.inject(InjectionManagerImpl.java:470)
        at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl.injectInstance(InjectionManagerImpl.java:171)
        at com.sun.ejb.containers.BaseContainer.injectEjbInstance(BaseContainer.java:1691)
        at com.sun.ejb.containers.MessageBeanContainer.createMessageDrivenEJB(MessageBeanContainer.java:706)
        at com.sun.ejb.containers.MessageBeanContainer.access$100(MessageBeanContainer.java:101)
        at com.sun.ejb.containers.MessageBeanContainer$MessageBeanContextFactory.create(MessageBeanContainer.java:483)
        at com.sun.ejb.containers.util.pool.NonBlockingPool.getObject(NonBlockingPool.java:247)
        at com.sun.ejb.containers.MessageBeanContainer._getContext(MessageBeanContainer.java:547)
        at com.sun.ejb.containers.BaseContainer.getContext(BaseContainer.java:2528)
        at com.sun.ejb.containers.MessageBeanContainer.beforeMessageDelivery(MessageBeanContainer.java:989)
        at com.sun.ejb.containers.MessageBeanListenerImpl.beforeMessageDelivery(MessageBeanListenerImpl.java:77)
        at com.sun.enterprise.connectors.inbound.MessageEndpointInvocationHandler.invoke(MessageEndpointInvocationHandler.java:139)
        at $Proxy337.beforeDelivery(Unknown Source)
        at com.sun.messaging.jms.ra.OnMessageRunner.run(OnMessageRunner.java:247)
        at com.sun.enterprise.connectors.work.OneWork.doWork(OneWork.java:114)
        at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.performWork(ThreadPoolImpl.java:497)
        at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:540)
Caused by: javax.naming.NamingException: Lookup failed for 'java:comp/env/my.package.MessageBeanOne/messageBeanTwo' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NamingException: Exception resolving Ejb for 'Remote ejb-ref name=my.package.MessageBeanOne/messageBeanTwo,Remote 3.x interface =my.package.MessageBeanTwo,ejb-link=null,lookup=,mappedName=,jndi-name=my.package.MessageBeanTwo,refType=Session' .  Actual (possibly internal) Remote JNDI name used for lookup is 'my.package.MessageBeanTwo#my.package.MessageBeanTwo' [Root exception is javax.naming.NamingException: Lookup failed for 'my.package.MessageBeanTwo#my.package.MessageBeanTwo' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NameNotFoundException: my.package.MessageBeanTwo#my.package.MessageBeanTwo not found]]]
        at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:518)
        at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:455)
        at javax.naming.InitialContext.lookup(InitialContext.java:392)
        at javax.naming.InitialContext.lookup(InitialContext.java:392)
        at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl._inject(InjectionManagerImpl.java:599)
        ... 17 more
Caused by: javax.naming.NamingException: Exception resolving Ejb for 'Remote ejb-ref name=my.package.MessageBeanOne/messageBeanTwo,Remote 3.x interface =my.package.MessageBeanTwo,ejb-link=null,lookup=,mappedName=,jndi-name=my.package.MessageBeanTwo,refType=Session' .  Actual (possibly internal) Remote JNDI name used for lookup is 'my.package.MessageBeanTwo#my.package.MessageBeanTwo' [Root exception is javax.naming.NamingException: Lookup failed for 'my.package.MessageBeanTwo#my.package.MessageBeanTwo' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NameNotFoundException: my.package.MessageBeanTwo#my.package.MessageBeanTwo not found]]
        at com.sun.ejb.EjbNamingReferenceManagerImpl.resolveEjbReference(EjbNamingReferenceManagerImpl.java:178)
        at com.sun.enterprise.container.common.impl.ComponentEnvManagerImpl$EjbReferenceProxy.create(ComponentEnvManagerImpl.java:1106)
        at com.sun.enterprise.naming.impl.GlassfishNamingManagerImpl.lookup(GlassfishNamingManagerImpl.java:776)
        at com.sun.enterprise.naming.impl.GlassfishNamingManagerImpl.lookup(GlassfishNamingManagerImpl.java:744)
        at com.sun.enterprise.naming.impl.JavaURLContext.lookup(JavaURLContext.java:172)
        at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:498)
        ... 21 more
Caused by: javax.naming.NamingException: Lookup failed for 'my.package.MessageBeanTwo#my.package.MessageBeanTwo' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NameNotFoundException: my.package.MessageBeanTwo#my.package.MessageBeanTwo not found]
        at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:518)
        at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:455)
        at javax.naming.InitialContext.lookup(InitialContext.java:392)
        at javax.naming.InitialContext.lookup(InitialContext.java:392)
        at com.sun.ejb.EjbNamingReferenceManagerImpl.resolveEjbReference(EjbNamingReferenceManagerImpl.java:173)
        ... 26 more
Caused by: javax.naming.NameNotFoundException: my.package.MessageBeanTwo#my.package.MessageBeanTwo not found
        at com.sun.enterprise.naming.impl.TransientContext.doLookup(TransientContext.java:248)
        at com.sun.enterprise.naming.impl.TransientContext.lookup(TransientContext.java:215)
        at com.sun.enterprise.naming.impl.SerialContextProviderImpl.lookup(SerialContextProviderImpl.java:77)
        at com.sun.enterprise.naming.impl.LocalSerialContextProviderImpl.lookup(LocalSerialContextProviderImpl.java:119)
        at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:505)
        ... 30 more
|#]

[#|2011-11-23T10:55:35.548-0700|WARNING|glassfish3.1.1|javax.resourceadapter.mqjmsra.inbound.message|_ThreadID=19;_ThreadName=Thread-2;|MQJMSRA_MR2001: run:Caught Exception from onMessage():Redelivering:
javax.ejb.EJBException: ESwimMessageBeanTwo-ear-1.0:MessageBeanOne: message-driven bean invocation closed by container
        at com.sun.ejb.containers.MessageBeanContainer.deliverMessage(MessageBeanContainer.java:1163)
        at com.sun.ejb.containers.MessageBeanListenerImpl.deliverMessage(MessageBeanListenerImpl.java:81)
        at com.sun.enterprise.connectors.inbound.MessageEndpointInvocationHandler.invoke(MessageEndpointInvocationHandler.java:171)
        at $Proxy337.onMessage(Unknown Source)
        at com.sun.messaging.jms.ra.OnMessageRunner.run(OnMessageRunner.java:260)
        at com.sun.enterprise.connectors.work.OneWork.doWork(OneWork.java:114)
        at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.performWork(ThreadPoolImpl.java:497)
        at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:540)
|#]

On trying to search if this is actually possible, I've come across lots of references to injecting MDBs into Session beans, but never injecting an MDB into another MDB. Maybe this isn't doable?

1
They are "message-driven" beans, why are you trying to inject one into another. Are you trying to call the onMessage() method yourself?Bhesh Gurung
MessageBeanTwo has a process() method that MessageBeanOne calls. He is not calling onMessage() but only this process() method.Gonzalo Garcia Lasurtegui
Initially, MessageBeanOne created a new instance of MessageBeanTwo to do the processing, but because it wasn't injected (and therefore not container managed) there were issues.sdoca
I edited the example to show that MessageBeanTwo also makes use of an injected EntityService object. If MessageBeanOne got a instance of MessageBeanTwo via "new", the EntityService is null. Hence the need to inject MessageBeanTwo into MessgeBeanOne. Hope that clarifies.sdoca

1 Answers

1
votes

Probably not directly related to the question, but I would extract the process() method to its own class that both MDBs can modify. This way MDBs have the sole responsibility of processing incoming messages and the third new class performs the "entity processing". This class could then be another EJB that you inject in both MDBs.

In my opinion, MDBs should generally be dedicated only to process receive messages.

EDIT

By looking at your code a second time, I would encourage you to think about it twice. Your MDBs have state and that could lead to unexpected results taking into account that the container creates a pool of instances. You could be in the situation where an instance of MessageBeanTwo is pooled with goodToProcess = false. If that instance is taken from the pool and injected in MessageBeanOne and process() method is called, you might get a wrong result.

This is all assuming you can inject an MDB in another one, which I have never done or heard of.