-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running org.superbiz.ejblookup.EjbDependencyTest
Apache OpenEJB 3.1.5-SNAPSHOT build: 20101129-09:51
http://tomee.apache.org/
INFO - openejb.home =
Lookup of other EJBs Example
Overview
This example shows how to configure JNDI to lookup other EJBs using either the `@EJB` annotation or the ejb-jar.xml deployment descriptor.
There are a couple interesting aspects in this example intended to flush out some of the more confusing, and perhaps frustrating, aspects of referring to EJBs.
-
beans themselves do not have JNDI names (this was only recently added in Java EE 6)
This is the most frustrating and hard to accept. Java EE 5 does not have a global namespace and therefore there is no singular name for your EJB. It does not matter what you do to your EJB, there is no standard way to "give" the bean a name that can be used by the application globally.
-
each EJB owns its own private java:comp/env namespace (java:comp/env is not global and cannot be treated that way)
-
names do not magically appear in java:comp/env, they must be explicitly added.
-
to get a reference to bean B in the java:comp/env namespace of bean A, bean A must declare a reference to bean B.
You read this right. If you have 10 EJBs and all of them want to refer to bean B, then you must declare bean B as a reference 10 times (once for each of the 10 beans). There is no standard way in Java EE 5 to do this just once for all beans. In Java EE 6 there is a "java:global" namespace, a "java:app" namespace, and a "java:module" namespace where names can be defined with the desired scope. Java EE 5 has only java:comp.
There are two things which make this even more confusing:
-
Servlets have always defined java:comp/env differently. In a webapp, the java:comp/env namespace is shared by all servlets. This is essentially equivalent to the java:module namespace in Java EE 6. Understand there is a conflict in definition here and that for EJBs, java:comp is scoped at the component (the EJB itself) not the module as with webapps.
-
All vendors have some proprietary concept of global JNDI. So you may be able to lookup "java:/MyBean" or "MyBeanLocal", but these are vendor-specific and non-portable.
As well this example shows some other interesting aspects of referring to EJBs:
-
Two beans may use the same business interfaces, the interface alone does not necessarily identify the exact bean
-
circular references are possible
To illustrate all of this, we have two simple @Stateless
beans,
RedBean and BlueBean. Both implement the same business local
interface, Friend. Both RedBean and BlueBean define
java:comp/env/myFriend differently which is allowed as java:comp is
a namespace that is private to each bean and not visible to other beans — so the names do not have to match.
The Code
Here we show the code for RedBean and BlueBean and their shared business local interface Friend. \{snippet:id=code|url=openejb3/examples/lookup-of-ejbs/src/main/java/org/superbiz/ejblookup/RedBean.java|lang=java} \{snippet:id=code|url=openejb3/examples/lookup-of-ejbs/src/main/java/org/superbiz/ejblookup/BlueBean.java|lang=java} \{snippet:id=code|url=openejb3/examples/lookup-of-ejbs/src/main/java/org/superbiz/ejblookup/Friend.java|lang=java}
The key items in the above are the following: - `@EJB` has been used at the class level to declare myFriend in the java:comp/env namespace of each EJB - because both beans share the same interface, Friend, we need to add beanName to the `@EJB` usage to specify the exact EJB we want - for BlueBean the java:comp/env/myFriend name has been configured to point to RedBean - for RedBean the java:comp/env/myFriend name has been configured to point to BlueBean
Alternative to annotations
If there is a desire to not use annotations, the above annotation usage is equivalent to the following ejb-jar.xml \{snippet:url=openejb3/examples/lookup-of-ejbs-with-descriptor/src/main/resources/META-INF/ejb-jar.xml|lang=xml}
Writing a unit test for the example
Writing an unit test for this example is quite simple. We need just to write a setup method to create and initialize the InitialContext, and then write our test methods
\{snippet:id=code|url=openejb3/examples/lookup-of-ejbs/src/test/java/org/superbiz/ejblookup/EjbDependencyTest.java|lang=java}
Running
Running the example is fairly simple. In the "lookup-of-ejbs" directory of the openejb:download.html[examples zip] , just run:
$ mvn clean install
Which should create output like the following.
/Users/dblevins/work/openejb-3.1.x/examples/lookup-of-ejbs INFO - openejb.base = /Users/dblevins/work/openejb-3.1.x/examples/lookup-of-ejbs INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service) INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager) INFO - Found EjbModule in classpath: /Users/dblevins/work/openejb-3.1.x/examples/lookup-of-ejbs/target/classes INFO - Beginning load: /Users/dblevins/work/openejb-3.1.x/examples/lookup-of-ejbs/target/classes INFO - Configuring enterprise application: classpath.ear INFO - Configuring Service(id=Default Stateless Container, type=Container, provider-id=Default Stateless Container) INFO - Auto-creating a container for bean BlueBean: Container(type=STATELESS, id=Default Stateless Container) INFO - Enterprise application "classpath.ear" loaded. INFO - Assembling app: classpath.ear INFO - Jndi(name=BlueBeanLocal) -→ Ejb(deployment-id=BlueBean) INFO - Jndi(name=RedBeanLocal) -→ Ejb(deployment-id=RedBean) INFO - Created Ejb(deployment-id=RedBean, ejb-name=RedBean, container=Default Stateless Container) INFO - Created Ejb(deployment-id=BlueBean, ejb-name=BlueBean, container=Default Stateless Container) INFO - Deployed Application(path=classpath.ear) Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.244 sec
Results :
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0