Enterprise Java Development@TOPIC@

Chapter 57. Configuring EJB using JNDI Lookups of ENC

57.1. Setup
57.2. Inject Resources
57.3. Summary

In this chapter we will keep populating the JNDI ENC via XML but we will revert back to an older configuration technique that requires a programmatic lookup of resources within the JNDI ENC. This technique allows for deployment of an EJB to be separated from the resource availability -- permitting a "lazy" lookup of the resources at runtime. It also blazes a trail for standard POJO classes to perform resource lookups within their hosting component's ENC.

The @Resource and @PersistenceContext injections so far work only with EJB bean classes. We want to show how standard POJO classes, embedded within the EJB bean, will also have access to resources without being coupled to a specific EJB or other JavaEE component type. The embedded POJO can use standard JNDI lookups to locate the resources within the local component's JNDI ENC context. Although this lab does not instantiate a POJO class for this purpose -- it does demonstrate what the POJO classes must do and places that code within the @PostConstruct. Since we are still within the EJB bean, we will be using a mixture of InitialContext/java:comp/env lookups and SessionContext lookups.

One other change made during this chapter is the movement of the lookup JNDI names have been moved to the vendor-specific META-INF/jboss-ejb3.xml file. The core/standard ENC configuration is placed within the META-INF/ejb-jar.xml and used on multiple platforms and platform configurations. The additional file would be unique to the JBoss platform and our specific configuration of JBoss resources.

We will primarily be working with the following files

src/
|-- main
|   |-- java
|   |   `-- org
|   |       `-- myorg
|   |           `-- encconfig
|   |               `-- ejb
|   |                   `-- JNDIAuditorEJB.java
|   `-- resources
|       `-- META-INF
|           |-- ejb-jar.xml
|           `-- jboss-ejb3.xml
`-- test
    |-- java
    |   `-- org
    |       `-- myorg
    |           `-- encconfig
    |               `-- auditor
    |                   `-- ejb
    |                       `-- it
    |                           `-- JNDIAuditorEJBIT.java
  1. Activate the JNDIAuditorEJBIT test case. Since this test case extends the same base class as the previous two test cases (where we activated all the test methods) all test methods will immediately become active.

    //TODO enc-config 17: activate this testcase 
    
    @Ignore
    public class JNDIAuditorEJBIT extends AuditorCheckerITBase {
  2. Re-run the IT tests for the EJB module. The test case you just activated above will fail with several errors

    java.lang.AssertionError: publishJMS value not injected
    java.lang.AssertionError: persistence context not injected
    java.lang.AssertionError: topic not injected
    java.lang.AssertionError: connection factory not injected
    java.lang.AssertionError: EJB not properly initialized expected:<2> but was:<0>
  3. Activate the PostCostruct initialization method for the EJB under test. This method depends on an injected SessionContext for doing ENC lookups and instantiates a default InitialContext to simulate what lower-level components can do with the java:comp/env namespace.

    @Stateless
    
    public class JNDIAuditorEJB extends AuditorBase 
    ...
    private @Resource SessionContext ctx;
    //TODO enc-config 18: activate initialization method to perform ENC lookups 
    //@PostConstruct
    public void init() {
        InitialContext jndi = null;
        try {
            jndi=new InitialContext();
    ...
        } catch (NamingException ex) {
            log.error("error looking up resources", ex);
            throw new EJBException("error looking up resources:" + ex);
        } finally {
            close(jndi);
        }
        super.setLog(log);
        super.setConnectionFactory(cf);
        super.setEntityManager(em);
        super.setTopic(topic);
        super.setPublishJMS(isPublishJMS());
    }
  4. Correct the first issue by looking up the value from the JNDI ENC placed there by the META-INF/ejb-jar.xml

    
    <session>
        <ejb-name>JNDIAuditorEJB</ejb-name>
        <env-entry>
            <env-entry-name>val/publishJMS</env-entry-name>
            <env-entry-type>java.lang.Boolean</env-entry-type>
            <env-entry-value>true</env-entry-value>
        </env-entry>
    ...
    </session>

    The value can be looked up using an injected SessionContext and the ENC name used by the XML and in the previous chapter. Perform a programmatic lookup of the ENC value and assign it to the publishJMS Java attribute.

    @Stateless
    
    public class JNDIAuditorEJB extends AuditorBase 
    ...
    //TODO enc-config 19: lookup resource value in ENC 
    //publishJMS = (Boolean) ctx.lookup("val/publishJMS");
  5. Re-deploy the EJB module using the maven cargo plugin

    $ mvn pre-integration-test
  6. Re-run the IT tests. The test you addressed above should now pass.

  7. Correct the next issue by looking up the persistence context from the JNDI ENC placed there by the META-INF/ejb-jar.xml

    
    <persistence-context-ref>
        <persistence-context-ref-name>jpa/em</persistence-context-ref-name>
        <persistence-unit-name>encconfig-lab</persistence-unit-name>
    </persistence-context-ref>

    Perform the ENC lookup using the injected SessionContext and the ENC name. Assign the value to the em Java attribute with the JNDIAuditorEJB class.

    @Stateless
    
    public class JNDIAuditorEJB extends AuditorBase 
    ...
    //TODO enc-config 20: lookup persistence context in ENC 
    //em = (EntityManager) ctx.lookup("jpa/em");

    Although it would be nicer to simply have the value injected as we did in the previous chapter -- the lookup is made simple using the injected SessionContext. This injected object is specific to being an EJB component and not available to all Java classes running in the server. We will address that aspect for the follow-on properties.

  8. Re-deploy the EJB module using the maven cargo plugin

    $ mvn pre-integration-test
  9. Re-run the IT tests. The test you addressed above should now pass.

  10. Correct the next issue by looking up the administered JMS topic from the JNDI ENC placed there by the META-INF/ejb-jar.xml

    
    <resource-env-ref>
        <resource-env-ref-name>jms/topic</resource-env-ref-name>
        <resource-env-ref-type>javax.jms.Topic</resource-env-ref-type>
    </resource-env-ref>

    The JNDI name is being supplied by the META-INF/jboss-ejb3.xml file.

    
    <?xml version="1.0"?>  
    <jboss:ejb-jar 
    ...
        <enterprise-beans>
            <session>
                <ejb-name>JNDIAuditorEJB</ejb-name>
    ...
                <resource-env-ref>
                    <resource-env-ref-name>jms/topic</resource-env-ref-name>
                    <resource-env-ref-type>javax.jms.Topic</resource-env-ref-type>
                    <jndi-name>java:/topic/test</jndi-name>
                </resource-env-ref>
            </session>
    </jboss:ejb-jar>

    Perform the ENC lookup using an InitialContext and the ENC name prefixed with java:comp/env. Assign the value to the topic Java attribute with the JNDIAuditorEJB class.

    //TODO enc-config 21: lookup resource in ENC using JNDI java:comp/env 
    
    //topic = (Topic) jndi.lookup("java:comp/env/jms/topic");

    Notice how this technique is independent of the code being within the EJB bean class. Any Java class can instantiate a default InitialContext and lookup the ENC for its hosting component using the "java:comp/env" context. This is functionally the same as using the the shorter name with the SessionContext.lookup() except that it can be used outside of the EJB.

  11. Re-deploy the EJB module using the maven cargo plugin

    $ mvn pre-integration-test
  12. Re-run the IT tests. The test you addressed above should now pass.

  13. Correct the next issue by looking up the administered JMS connection factory from the JNDI ENC placed there by the META-INF/ejb-jar.xml

    
    <resource-ref>
        <res-ref-name>jms/cf</res-ref-name>
        <res-type>javax.jms.ConnectionFactory</res-type>
    </resource-ref>

    The JNDI name is being supplied by the jboss-ejb3.xml file.

    
    
    <resource-ref>
        <res-ref-name>jms/cf</res-ref-name>
        <res-type>javax.jms.ConnectionFactory</res-type>
        <jndi-name>java:/JmsXA</jndi-name>
    </resource-ref>

    Perform the ENC lookup using the InitialContext and the ENC name prefixed with java:comp/env. Assign the value to the cf Java attribute with the JNDIAuditorEJB class.

    //TODO enc-config 22: lookup resource in ENC using JNDI java:comp/env
    
    //cf = (ConnectionFactory) jndi.lookup("java:comp/env/jms/cf");
  14. Re-deploy the EJB module using the maven cargo plugin

    $ mvn pre-integration-test
  15. Re-run the IT tests. This time all tests for the JNDIAuditorEJBIT test case should now pass -- including the testAudit since all resources have now been injected and the @PostConstruct method has been activated to push those resources up the to base class helper.

You have finished configuring your EJB using programmatic JNDI lookups of resources populated in the ENC using XML descriptor files.

In this chapter you successfully activated a @PostConstruct method in the EJB bean class that performed programmatic JNDI lookups of the ENC using an injected SessionContext and alternately an InitialContext. Lookups that used the SessionContext could use the core ENC name. Lookups that used the InitialContext had to prefix the ENC name with the string java:comp/env/. The SessionContext is unique to being an EJB class. The InitialContext can be used by any Java class delegated to by the EJB.

This technique has the benefit of keeping the global/physical JNDI names away from the Java classes but requires a programmatic lookup -- rather than injection. This would only be desirable for helper classes delegated to by the EJB. In the next section we will use a declarative approach that requires no knowledge of any resource injection by the EJB bean. All will be handled by the XML deployment descriptor.