views:

996

answers:

3

I'm reasonably new to JEE, so this might be stupid.. bear with me pls :D

I would like to inject a stateless session bean into a message-driven bean. Basically, the MDB gets a JMS message, then uses a session bean to perform the work. The session bean holds the business logic.

Here's my Session Bean:

@Stateless
public class TestBean implements TestBeanRemote {

  public void doSomething() {
    // business logic goes here
  }
}

The matching interface:

@Remote
public interface TestBeanRemote {

  public void doSomething();
}

Here's my MDB:

@MessageDriven(mappedName = "jms/mvs.TestController", activationConfig =  {
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
    })
public class TestController implements MessageListener {

 @EJB
 private TestBean testBean;

    public TestController() {
    }

    public void onMessage(Message message) {
      testBean.doSomething();
    }
}

So far, not rocket science, right?

Unfortunately, when deploying this to glassfish v3, and sending a message to the appropriate JMS Queue, I get errors that glassfish is unable to locate the TestBean EJB:

java.lang.IllegalStateException: Exception attempting to inject Remote ejb-ref name=mvs.test.TestController/testBean,Remote 3.x interface =mvs.test.TestBean,ejb-link=null,lookup=null,mappedName=,jndi-name=mvs.test.TestBean,refType=Session into class mvs.test.TestController
Caused by: com.sun.enterprise.container.common.spi.util.InjectionException: Exception attempting to inject Remote ejb-ref name=mvs.test.TestController/testBean,Remote 3.x interface =mvs.test.TestBean,ejb-link=null,lookup=null,mappedName=,jndi-name=mvs.test.TestBean,refType=Session into class mvs.test.TestController
Caused by: javax.naming.NamingException: Lookup failed for 'java:comp/env/mvs.test.TestController/testBean' in SerialContext  [Root exception is javax.naming.NamingException: Exception resolving Ejb for 'Remote ejb-ref name=mvs.test.TestController/testBean,Remote 3.x interface =mvs.test.TestBean,ejb-link=null,lookup=null,mappedName=,jndi-name=mvs.test.TestBean,refType=Session' .  Actual (possibly internal) Remote JNDI name used for lookup is 'mvs.test.TestBean#mvs.test.TestBean' [Root exception is javax.naming.NamingException: Lookup failed for 'mvs.test.TestBean#mvs.test.TestBean' in SerialContext  [Root exception is javax.naming.NameNotFoundException: mvs.test.TestBean#mvs.test.TestBean not found]]]

So my questions are:

  • is this the correct way of injecting a session bean into another bean (particularly a message driven bean)?
  • why is the naming lookup failing?
A: 

Ok, I found out that if I add the annotation @LocalBean to the session bean, it works. What the ...?

Hank
I'm a bit further now. @LocalBean identifies a bean without an Interface. So this is not what I want, even though it works :D
Hank
+1  A: 

Could you try to define things like this:

@Remote
public interface TestBeanRemote {

  public void doSomething();
}

@Stateless(name="TestBeanRemote")
public class TestBean implements TestBeanRemote {

  public void doSomething() {
    // business logic goes here
  }
}

And then in the MDB:

@MessageDriven(mappedName = "jms/mvs.TestController", activationConfig =  {
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
    })
public class TestController implements MessageListener {

    @EJB(beanName="TestBeanRemote")
    private TestBeanRemote testBean;

    public TestController() {
    }

    public void onMessage(Message message) {
      testBean.doSomething();
    }
}

If this work, I'll try to provide an explanation :)

Pascal Thivent
Sorry, unfortunately that doesn't work either. I think I'll go with what I found out about IoC. Thanks anyway!
Hank
@Hank Weird, my understanding it that it should. I'm confused...
Pascal Thivent
+1  A: 

It seems that my problem was related to Inversion of Control and caused by my lack of knowledge and Netbeans' suggestions for Class/Interface names.

I found out that - in order to find the the right bean and the right interface - I should name them properly. Here's what works:

@Remote
public interface Test {

  public void doSomething();
}

@Stateless
public class TestBean implements Test {

  public void doSomething() {
    // business logic goes here
  }
}

And in the MDB I access 'Test' not 'TestBean':

@MessageDriven(mappedName = "jms/mvs.TestController", activationConfig =  {
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
    })
public class TestController implements MessageListener {

    @EJB
    private Test testBean;

    public TestController() {
    }

    public void onMessage(Message message) {
      testBean.doSomething();
    }
}
Hank
Can you add any reference on your findings about naming conventions?
Pascal Thivent
Try here: http://java.sun.com/blueprints/code/namingconventions.html
Hank
Ok, I'm starting to understand this more and more now. My example above would be correct, if the interface would be @Local.When I inject a session bean into something, I'm injecting <component-name>. The container then tries to find the implementing class (<component-name>Bean) as well as the appropriate interface (for @Local use: <component-name> or <component-name>Local, for @Remote use: <component-name>Remote).So the problem wasn't JNDI, it was not complying with the naming conventions!
Hank

related questions