| h1. 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. |
| |
| |
| h1. 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}} |
| |
| h2. 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} |
| |
| h1. 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} |
| |
| h1. Running |
| |
| Running the example is fairly simple. In the "lookup-of-ejbs" directory of the [examples zip|OPENEJB:Download], just run: |
| |
| {quote} |
| $ mvn clean install |
| {quote} |
| |
| Which should create output like the following. |
| |
| {noformat} |
| ------------------------------------------------------- |
| T E S T S |
| ------------------------------------------------------- |
| Running org.superbiz.ejblookup.EjbDependencyTest |
| Apache OpenEJB 3.1.5-SNAPSHOT build: 20101129-09:51 |
| http://openejb.apache.org/ |
| INFO - openejb.home = /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 |
| {noformat} |
| |