Enterprise Java Development@TOPIC@
Naming - provides a "white pages" lookup of an object based on name
Directory - provides a "yellow pages" lookup of an object based on properties
JavaEE providers required to supply Naming implementation
Naming consists of hierarchical Contexts (directories) and Objects
Reference to JNDI Naming tree through javax.naming.InitialContext
InitialContext jndi = null;
try {
jndi = new InitialContext();
...
Object object = jndi.lookup(jndiName);
} catch (NamingException ex) {
throw new EJBException(ex);
}
Lookups are passed a JNDI name
JNDI name have prefixes that can give them special meaning
(no prefix) - global namespace (available remotely)
java: - namespace available only within JVM
java:comp - an Enterprise Naming Context (ENC) relative to a specific component
ejb: - namespace for use by JBoss EJB Client
JavaEE resources are registered in the JNDI tree
Not all resources are available from remote clients
Resources in the global JNDI Naming Context are available to all clients
jms/RemoteConnectionFactory jms/queue/test jms/topic/test enc-config-example-ejb/XMLConfiguredEJB!ejava.ejb.examples.encconfig.ejb.JNDIReaderRemote
You can locate these global names using the java:/jboss/exported local context
java:jboss/exported/jms/RemoteConnectionFactory java:jboss/exported/jms/queue/test java:jboss/exported/jms/topic/test java:jboss/exported/enc-config-example-ejb/XMLConfiguredEJB!ejava.ejb.examples.encconfig.ejb.JNDIReaderRemote
Resources in the local JNDI Naming Context are available to components within the server
java:jboss/datasources/ExampleDS java:jboss/jaxr/ConnectionFactory java:jboss/mail/Default java:/ConnectionFactory java:/JmsXA java:/queue/test java:/topic/test
JavaEE 6/EJB3.1 added a portable JNDI naming standard for EJB that provides scoping for global, application, and module for the EJB's local and remote interfaces
java:global/enc-config-example-ejb/InjectedEJB!ejava.ejb.examples.encconfig.ejb.InjectedEJB java:app/enc-config-example-ejb/InjectedEJB!ejava.ejb.examples.encconfig.ejb.InjectedEJB java:module/InjectedEJB!ejava.ejb.examples.encconfig.ejb.InjectedEJB java:global/enc-config-example-ejb/InjectedEJB java:app/enc-config-example-ejb/InjectedEJB java:module/InjectedEJB
Component-specific namespace within JNDI tree
Holds references to values and objects in the environment
Theoretical equivalent to Unix soft links
ln -s <some physical file path> $HOME/<my logical path>
Accessible through "java:comp/env/(encname)" when using InitialContext
Context jndi = new InitialContext();
String jndiName = "java:comp/env/" + encname;
Object object = jndi.lookup(jndiName);
Accessible through "(encname)" when using injected SessionContext
private @Resource SessionContext ctx;
...
Object object = ctx.lookup(encname);
Populated into ENC using
The only reason to purposely populate the ENC is to support ENC lookups. Purposely populating the ENC is not necessary for alternate injection techniques.
Annotations
@Resource(lookup="java:jboss/datasources/ExampleDS", name="jdbc/ds2")
private DataSource ds2;
The annotation is looking up the potentially non-portable, local (java:) JNDI name from the global JNDI tree and making it available in the ENC (java:comp/env) in addition to injecting it into the Java variable. The later addition of the "lookup" annotation attribute (which may use a vendor-specific JNDI name) to injections in the EJB spec made configuring simple cases simple.
XML using META-INF/ejb-jar.xml
<resource-ref>
<res-ref-name>jdbc/ds2</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<lookup-name>java:jboss/datasources/ExampleDS</lookup-name>
</resource-ref>
The standard EJB deployment descriptor is looking up the potentially non-portable, local (java:) JNDI name from the global JNDI tree and making it available in the ENC (java:comp/env) The later addition of the "lookup-name" XML attribute (which may use a vendor-specific JNDI name) in the EJB spec eliminated the need for vendor-specific deployment descriptors for simple cases like this.
XML using META-INF/jboss-ejb3.xml
<resource-ref>
<res-ref-name>jdbc/ds3</res-ref-name>
<jndi-name>java:jboss/datasources/ExampleDS</jndi-name>
</resource-ref>
The vendor-specific EJB deployment descriptor is looking up the potentially non-portable, local (java:) JNDI name from the global JNDI tree and making it available in the ENC (java:comp/env) This is where potentially non-portable JNDI names had to be supplied in the original EJB specs.
Injected into EJB using
In these cases, we are purposely injecting the resource directly into the variable without a concern for the ENC.
Annotations without ENC
@Resource(lookup="java:jboss/datasources/ExampleDS")
private DataSource ds1;
Performing the injection into the Java field 100% within the code
Good for quick cases where developer knows the JNDI name of the resource and wants it injected into the variable
Code must be updated whenever the JNDI name of the resource changes
Annotations with populated ENC
@Resource(name="jdbc/ds3")
private DataSource ds3;
Performing the injection into the Java field using a portable ENC reference (java:comp/env/jdbc/ds3)
Adds a requirement for ENC to be populated
Code is portable and only ENC setup mechanism must be ported
XML using META-INF/ejb-jar.xml
<resource-ref>
<res-ref-name>jdbc/ds1</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<injection-target>
<injection-target-class>ejava.ejb.examples.encconfig.ejb.XMLConfiguredEJB</injection-target-class>
<injection-target-name>ds1</injection-target-name>
</injection-target>
<lookup-name>java:jboss/datasources/ExampleDS</lookup-name>
</resource-ref>
Populates the ENC (java:comp/env/jdbc/ds1) as before
Also performs injection into the EJB Java field using a standard XML deployment descriptor
EJB code is portable. Just the descriptor needs updating on change.
Injections are fairly basic. e.g., cannot inject into an object embedded within the EJB or define a global injection rule.
Perform actions on injected resources after injection
complete using @PostConstruct
@Resource(lookup="java:jboss/datasources/ExampleDS")
private DataSource ds1;
private SomeDao someDao;
@PostConstruct
public void init() {
//ds1 already injected -or-
ds1 = (DataSource)ctx.lookup("jdbc/ds1"); //-or-
ds1 = (DataSource)jndi.lookup("java:comp/env/jdbc/ds1"); //-or-
someDao = new SomeDaoImpl(ds1);
...
}
Call Order:
Properties are injected
@PostConstruct is invoked