Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java EE 6 - Embedded container EJB tests

This questiong is regarding Java EE 6, using glassfish v3 embedded-all.

I have a unit test that uses EJBContainer to test my stateless EJB. Problem is I'm having trouble looking up the EJB (remote) using JNDI:

setup() {

  ctx = EJBContainer.createEJBContainer().getContext();

}

...

test() {

BookService bookService = (BookService)ctx.lookup("java:global/BookServiceEJB!com.something.service.BookService");

...

}

@Stateless
public class BookServiceEJB implements BookService {
...
}

@Remote
public interface BookService {
...
}

gives the exception:

javax.naming.NamingException: Lookup failed for 'java:global/BookServiceEJB!com.something.service.BookService' in SerialContext  [Root exception is javax.naming.NameNotFoundException: BookServiceEJB!com.something.service.BookService not found]

...

caused by: javax.naming.NameNotFoundException: BookServiceEJB!com.something.service.BookService not found

I have tried several JNDI resource paths:

e.g.

java:global/BookServiceEJB

java:global/BookService

even:

java:global/BookShelf-1.0-SNAPSHOT/BookServiceEJB

etc...

nothings works

I do not have any xml deployment files configured, only a persistence.xml in META-INF.

The test is using maven surefire:

mvn clean test

Any help is greatly appreciated!

Note: a full deploy to Glassfish server works (using appclient, and @EJB injection)

like image 822
Dzhu Avatar asked Dec 21 '22 22:12

Dzhu


2 Answers

After much searching, found the solution that works for me...

You'll have to configure the EJBContainer with the property: EJBContainer.MODULES, and the location where the module classes are (if using maven, 'target/classes').

e.g.

...
props = new Properties();
props.put(EJBContainer.MODULES, new File("target/classes"));
ec = EJBContainer.createEJBContainer(props);
...

If your EJB uses JPA, theres another problem in that you will not be able to define a datasource in the embedded container, so have to use the default ds: 'jdbc/__default'.

so for example my persistence.xml looks like so:

<?xml version="1.0" encoding="UTF-8"?>

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    version="1.0">

    <persistence-unit name="bookshelf" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>com.blah.domain.Book</class>
        <jta-data-source>jdbc/__default</jta-data-source>
        <properties>
            <property name="eclipselink.logging.level" value="INFO"/>
        </properties>
    </persistence-unit>

</persistence> 

I haven't figured out how to configure the embedded container test to use one DS (jdbc/__default), and my app to use another (e.g. jdbc/booksDS)

see: http://www.mentby.com/glassfish/embedded-testing-woes.html

see: http://forums.java.net/jive/thread.jspa?messageID=395759

To be honest I don't know why people are bothering with Java EE when solutions like spring is so much simpler...

It has been very frustrating and alot of time wasted... hope this helps.

like image 144
Dzhu Avatar answered Dec 28 '22 06:12

Dzhu


There's a few items you need to check in order to make sure you can load the bean through the context.lookup avoiding a NamingException.

  1. Make sure you have a bean. This may sound something obvious but I spent a lot of time trying to figure out why I wasn't able to get an instance of my service in the tests. The reason was that I was missing the Stateless annotation.

  2. Add the module when creating the container as @Dzhu pointed out. For maven classes will be target/classes, for maven tests will be target/test-classes.

  3. Something is wrong if you find a message like SEVERE: EJB6005:No EJB modules found in the console. It tells you that there are no Stateless annotated classes

  4. Take a look at the embedded glassfish console! In there you will see the lookup names for your beans. Pay attention to the messages in the format INFO: EJB5181:Portable JNDI names for EJB YourBean: [java:global/classes/YourBean!bean.package.YourBean, java:global/classes/YourBean]. That means you can lookup your bean either by calling context.lookup("java:global/classes/YourBean!bean.package.YourBean") or by the shorter name context.lookup("java:global/classes/YourBean") which can be useful if there's no name collisions.

Hope this helps someone. It would have been really helpful to have had this tips.

like image 24
Jonathan Morales Vélez Avatar answered Dec 28 '22 06:12

Jonathan Morales Vélez