Enterprise Java Development@TOPIC@

Chapter 59. EJB Injection

59.1. Setup
59.2. @EJB Inject No Interface EJB
59.3. @EJB Inject Local Interface Bean
59.4. @EJB Inject Remote Interface using Lookup
59.5. Summary

In the previous chapters we covered several techniques that can be used to configure EJBs with different types of resources. In this chapter we will limit the number of options but have you configure a new type of property -- a dependency EJB. EJBs can be injected with the @EJB annotation. If there is only one choice for the type of EJB and it is available within the local application, then all we need is the annotation. If there are multiple choices, we must identify which choice to make using either:

If the EJB is only available from a remote application, then we must use some form of JNDI lookup.

We will primarily be working with the following files

src
|-- main
|   |-- java
|   |   `-- org
|   |       `-- myorg
|   |           `-- encconfig
|   |               `-- ejb
|   |                   |-- Choice1EJB.java
|   |                   |-- Choice2EJB.java
|   |                   |-- ConfigBeanEJB.java
|   |                   |-- ConfigBeanRemote.java
|   |                   |-- SampleLocal.java
|                       |-- SampleNoIfaceEJB.java
|                       `-- SampleRemote.java
`-- test
    |-- java
    |   `-- org
    |       `-- myorg
    |           `-- encconfig
    |               `-- auditor
    |                   `-- ejb
    |                       `-- it
    |                           `-- ConfigBeanIT.java

In this section we are going to demonstrate how we can simply use an @EJB annotation and type information for the container to inject a dependency EJB instance into our parent EJB.

  1. Remove the @Ignore on the ConfigBeanIT test case.

    //TODO: enc-config 29
    
    @Ignore
    public class ConfigBeanIT {
  2. Re-run the IT tests. You should get a failure for the test case you just activated.

    java.lang.IllegalStateException: EJBCLIENT000025: No EJB receiver available for handling 
    [appName:, moduleName:encconfig-labex-ejb, distinctName:] 
    combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext@5000cc80

    The error basically states there is no EJB posted to the given JNDI name. This is because the EJB module was deployed without adding @Stateless to the EJB we are trying to lookup.

  3. Activate the EJB within the EJB module by adding @Stateless to the ConfigBeanEJB.

    //TODO: enc-config 30
    
    //@Stateless
    public class ConfigBeanEJB implements ConfigBeanRemote {
  4. Re-deploy the EJB module to the server.

    $ mvn pre-integration-test
  5. Re-run the JUnit tests. The following error should occur.

    no interface EJB not injected

    The error is caused by no injection defined for the EJB. In this case we want to use a "no interface" EJB that has no local interface -- so we inject the EJB class itself.

    private SampleNoIfaceEJB noIface;
  6. Add injection of the no interface EJB by adding an @EJB annotation. This will trigger the container to look for a SampleNoIfaceEJB, locate it, and inject it.

    @Stateless
    
    public class ConfigBeanEJB implements ConfigBeanRemote {
        //TODO: enc-config 31
        //@EJB
        private SampleNoIfaceEJB noIface;
  7. Re-deploy the EJB module to the server.

    $ mvn pre-integration-test
  8. Re-run the JUnit tests. The test case should now pass.

You have finished injecting a dependency EJB using just an @EJB annotation and type information from the Java variable. We happen to use a no interface bean in this example but the same can be done with @Local and @Remote interfaces as long as the dependency EJB is deployed within the application.

In this section we are going to demonstrate what can happen when there are multiple valid choices and how we can distinguish the right one by using its EJB name.

You have finished injecting a dependency EJB using an EJB beanName. The beanName (or other techniques) is required when the type-alone is not clear enough to locate the right dependency EJB.

In this section we are going to again demonstrate an ambiguity for an interface type except this time we will use a @Remote interface and dis-ambiguate the choices using the JNDI name of the target EJB using the lookup property of @EJB.

  1. Update the Choice1EJB to also implement the SampleRemote interface.

    @Stateless
    
    //TODO: enc-config 34
    public class Choice1EJB implements SampleLocal/*, SampleRemote*/ {

    This will again cause an ambiguity conflict now that we have two EJBs that implement the same interface.

        @EJB
    
        private SampleRemote remoteEJB;
  2. Attempt to re-deploy the EJB module to the server. This will fail.

    More than one EJB found with interface of type 'org.myorg.encconfig.ejb.SampleRemote' 
    for binding org.myorg.encconfig.ejb.ConfigBeanEJB/remoteEJB. Found: ...
  3. Fix the ambiguity by explicitly referencing Choice2EJB using one of its remote JNDI lookup names in the @EJB annotation. Since the EJB is local to the module -- we have the choice of several JNDI names to locate the EJB. The remote name in the "java:jboss/exported" namespace is the only one available to remote clients outside of the server.

    java:global/encconfig-labex-ejb/Choice2EJB!org.myorg.encconfig.ejb.SampleRemote
    java:app/encconfig-labex-ejb/Choice2EJB!org.myorg.encconfig.ejb.SampleRemote
    java:module/Choice2EJB!org.myorg.encconfig.ejb.SampleRemote
    java:jboss/exported/encconfig-labex-ejb/Choice2EJB!org.myorg.encconfig.ejb.SampleRemote
    
    @Stateless
    
    public class ConfigBeanEJB implements ConfigBeanRemote {
        //TODO: enc-config 35
        @EJB//(lookup="java:module/Choice2EJB!org.myorg.encconfig.ejb.SampleRemote")
        private SampleRemote remoteEJB;
  4. Re-deploy the application. This should succeed.

    $ mvn clean pre-integration-test
  5. Re-run the JUnit tests. This should also work.

You have finished injecting a dependency EJB using a JNDI lookup.

In this chapter you successfully injected a dependency EJB into a parent EJB thru a few different but simple techniques. The simplest technique was to use @EJB and the type information of the Java variable to completely wire-up the injection. That works until there is an ambiguity of choices or if the EJB is not deployed within the local application. Ambiguity can be solved using the beanName, JNDI lookup, or ENC name (we did not demonstrate this option). If the EJB is not deployed within the same module or application, we must use the lookup name to reference the JNDI name in a separate deployment.