Skip Headers
Oracle® Application Server Containers for J2EE Services Guide
10g Release 2 (10.1.2) for Windows or UNIX
B14012-02
  Go To Documentation Library
Library
Go To Product List
Product
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

2 Java Naming and Directory Interface

This chapter describes the Java Naming and Directory Interface (JNDI) service that is implemented by Oracle Application Server Containers for J2EE (OC4J) applications. It covers the following topics:

Introduction

JNDI, part of the J2EE specification, provides naming and directory functionality for Java applications. Because JNDI is defined independently of any specific naming or directory service implementation, it enables Java applications to access different naming and directory services using a single API. Different naming and directory service provider interfaces (SPIs) can be plugged in behind this common API to handle different naming services.

Before reading this chapter, you should be familiar with the basics of JNDI and the JNDI API. For basic information about JNDI, including tutorials and the API documentation, visit the Sun Microsystems Web site at:

http://java.sun.com/products/jndi/index.html

A JAR file implementing JNDI, jndi.jar, is available with OC4J. Your application can take advantage of the JNDI API without having to provide any other libraries or JAR files. A J2EE-compatible application uses JNDI to obtain naming contexts that enable the application to locate and retrieve objects such as data sources, Java Message Service (JMS) services, local and remote Enterprise Java Beans (EJBs), and many other J2EE objects and services.


Note:

For information about controlling access to JNDI namespaces, see the Oracle Application Server Security Guide.

Initial Context

The concept of the initial context is central to JNDI. Here are the two most frequently used JNDI operations in J2EE applications:

  • Creating a new InitialContext object (in the javax.naming package)

  • Using the InitialContext, to look up a J2EE or other resource

When OC4J starts up, it constructs a JNDI initial context for each application by reading resource references in the configuration XML file of each application.


Note:

After the initial configuration, the JNDI tree for each application is purely memory-based. Additions made to the context at run time are not persisted. When OC4J is restarted, additional bindings made by the application components to the JNDI name space, such as making a Context.bind API call in application code, are no longer available. However, anything that is bound declaratively through the various XML files is reconstructed upon startup.

Example

The following example shows two lines of Java code to use on the server side in a typical Web or EJB application:

Context ctx = new InitialContext();
myEJBHome myhome = 
        (HelloHome) ctx.lookup("java:comp/env/ejb/myEJB");

The first statement creates a new initial context object, using the default environment. The second statement looks up an EJB home interface reference in the JNDI tree of the application. In this case, myEJB might be the name of a session bean that is declared in the web.xml (or orion-web.xml) configuration file, in an <ejb-ref> tag. For example:

<ejb-ref>
  <ejb-ref-name>ejb/myEJB</ejb-ref-name>
  <ejb-ref-type>Session</ejb-ref-type>
  <home>myEjb.HelloHome</home>
  <remote>myEjb.HelloRemote</remote>
</ejb-ref>

This chapter focuses on setting up the initial contexts for using JNDI and describing how OC4J performs JNDI lookups. For more information about the other JNDI classes and methods, see the Javadoc at:

http://java.sun.com/products/jndi/1.2/javadoc/index.html

Constructing a JNDI Context

When OC4J starts up, it constructs a JNDI context for each application that is deployed in the server. There is always at least one application for an OC4J server, the global application, which is the default parent for each application in a server instance. User applications inherit properties from the global application and can override property values defined in the global application, define new values for properties, and define new properties as required.

For more information about configuring the OC4J server and its contained applications, see the Oracle Application Server Containers for J2EE User's Guide.


Note:

During EJB deployment in OC4J, you load the bean class to find out its methods so that you can generate EJB wrappers. Because the code in the static block is executed as the class is being loaded, the JNDI environment context is not yet set up. Even during runtime, the bean is in the "does not exist" stage. In this stage of the life cycle, the JNDI environment context is undefined, and the bean provider cannot rely on it to be available.

To work around this problem, set up and cache the context either during the construction of the bean, in the ejbCreate() method, or in the setSessionContext() method.


The environment that OC4J uses to construct a JNDI initial context can be found in three places:

The JNDI Environment

The JNDI InitialContext has two constructors:

InitialContext()
InitialContext(Hashtable env)

The first constructor creates a Context object, using the default context environment. If you use this constructor in an OC4J server-side application, then OC4J creates the initial context when the server is started, using the default environment for that application. This constructor is typically used in code that runs on the server side, such as in a JSP, EJB, or servlet.

The second constructor takes an environment parameter. You normally use the second form of the InitialContext constructor in client applications, where it is necessary to specify the JNDI environment. The env parameter in this constructor is a java.util.Hashtable that contains properties required by JNDI. Table 2-1 lists these properties, which are defined in the javax.naming.Context interface.

Table 2-1 InitialContext Properties

Property Meaning
INITIAL_CONTEXT_FACTORY Value for the java.naming.factory.initial property. This property specifies which initial context factory to use when creating a new initial context object.
PROVIDER_URL Value for the java.naming.provider.url property. This property specifies the URL that the application client code uses to look up objects on the server. Also used by RMIInitialContextFactory and ApplicationClientInitialContextFactory to search for objects in different applications. See Table 2-2, "JNDI-Related Environment Properties" for details.
SECURITY_PRINCIPAL Value for the java.naming.security.principal property. This property specifies the user name. Required in application client code to authenticate the client. Not required for server-side code, because the authentication has already been performed.
SECURITY_CREDENTIAL Value for the java.naming.security.credential property. This property specifies the password. Required in application client code to authenticate the client. Not required for server-side code, because the authentication has already been performed.

See "Accessing Objects from an Application Client" for a code example that sets these properties and gets a new JNDI initial context.

Creating the Initial Context in OC4J

Section 9.1 of the J2EE 1.3 specification defines application clients as follows:

"... first tier client programs that execute in their own Java virtual machines. Application clients follow the model for Java technology-based applications: they are invoked at their main method and run until the virtual machine is terminated. However, like other J2EE application components, application clients depend on a container to provide system services. The application client container may be very light-weight compared to other J2EE containers, providing only the security and deployment services described [in this specification]."

The following sections describe the ways in which JNDI initial contexts can be used:

From J2EE Application Clients

When an application client must look up a resource that is available in a J2EE server application, the client uses ApplicationClientInitialContextFactory in the com.evermind.server package to construct the initial context.


Note:

If your application is a J2EE client (that is, it has an application-client.xml file), then you must always use ApplicationClientInitialContextFactory regardless of the protocol (ORMI or IIOP) that the client application is using. The protocol itself is specified by the JNDI property java.naming.provider.url. See Table 2-2, "JNDI-Related Environment Properties" for details.

Consider an application client that consists of Java code running outside the OC4J server, and is also part of a bundled J2EE application. For example, the client code is running on a workstation and might connect to a server object, such as an EJB, to perform some application task. In this case, the environment that is accessible to JNDI must specify the value of the property java.naming.factory.initial as ApplicationClientInitialContextFactory. This can be specified in client code, or it can be specified in the jndi.properties file that is part of the application-client.jar file included in the EAR file.

To have access to remote objects that are part of the application, ApplicationClientInitialContextFactory reads the META-INF/application-client.xml and META-INF/orion-application-client.xml files in the application-client.jar file.

When clients use the ApplicationClientInitialContextFactory to construct JNDI initial contexts, they can look up local objects (objects contained in the immediate application or in its parent application) using the java:comp/env mechanism and RMIInitialContextFactory. They can then use ORMI or IIOP to invoke methods on these objects. Note that objects and resources must be defined in deployment descriptors in order to be bound to the JNDI context of an application.

Environment Properties

If the ORMI protocol is being used, ApplicationClientInitialContextFactory reads the properties listed in Table 2-2 from the environment.

Table 2-2 JNDI-Related Environment Properties

Property Meaning
dedicated.rmicontext This property replaces the deprecated dedicated.connection setting. When two or more clients in the same process retrieve an InitialContext, OC4J returns a cached context. Thus, each client receives the same InitialContext, which is assigned to the process. Server lookup, which results in server load balancing, happens only if the client retrieves its own InitialContext. If you set dedicated.rmicontext=true, then each client receives its own InitialContext instead of a shared context. When each client has its own InitialContext, then the clients can be load balanced.

The dedicated.rmicontext property defaults to false.

java.naming.provider.url This property specifies the URL to use when looking for local or remote objects. The format is either [http: | https:]ormi://hostname/appname or corbaname:hostname:port. For details on the corbaname URL, see "The corbaname URL" .

You can supply multiple hosts (for failover) in a comma-separated list.

java.naming.factory.url.pkgs Some versions of the JDK on some platforms automatically set the system property java.naming.factory.url.pkgs to include com.sun.java.*. Check this property and remove com.sun.java.* if it is present.
http.tunnel.path This property specifies an alternative RMIHttpTunnelServlet path. The default path is /servlet/rmi, as bound to the target site Web application. For more information, see "Configuring ORMI Tunneling through HTTP".
Context.SECURITY_PRINCIPAL This property specifies the user name and is required in client-side code to authenticate the client. It is not required for server-side code because authentication has already been performed. This property name is also defined as java.naming.security.principal.
Context.SECURITY_CREDENTIAL This property specifies the password and is required in client-side code to authenticate the client. It is not required for server-side code because authentication has already been performed. This property name is also defined as java.naming.security.credentials.

Accessing Objects from an Application Client

This section contains an example of how to configure an application client to access an EJB running inside an OC4J instance in the same location.

First, the EJB is deployed into OC4J. Here are excerpts of the deployment descriptors of the EJB.The EJB is deployed with the name EmployeeBean. The name is defined this way in ejb-jar.xml:

<ejb-jar>
  <display-name>bmpapp</display-name>
  <description>
     An EJB app containing only one Bean Managed Persistence Entity Bean
  </description>
  <enterprise-beans>
     <entity>
        <description>no description</description>
        <display-name>EmployeeBean</display-name>
        <ejb-name>EmployeeBean</ejb-name>
        <home>bmpapp.EmployeeHome</home>
        <remote>bmpapp.Employee</remote>
        <ejb-class>bmpapp.EmployeeBean</ejb-class>
        <persistence-type>Bean</persistence-type>
        ...
     </entity>
  </enterprise-beans>
..
</ejb-jar>

The EJB EmployeeBean is bound to the JNDI location java:comp/env/bmpapp/EmployeeBean in orion-ejb-jar.xml:

orion-ejb-jar.xml file:

<orion-ejb-jar>
   <enterprise-beans>
       <entity-deployment name="EmployeeBean"
           location="bmpapp/EmployeeBean" table="EMP">
                        ...
       </entity-deployment>
                        ...
   </enterprise-beans>
           ...
</orion-ejb-jar>

The application client program uses the EmployeeBean EJB, and refers to it as EmployeeBean. An excerpt from the application client program follows:

public static void main (String args[])
{
 ...
 Context context = new InitialContext();
 /**
  * Look up the EmployeeHome object. The reference is retrieved from the
  * application-local context (java:comp/env). The variable is
  * specified in the assembly descriptor (META-INF/application-client.xml).
  */
 Object homeObject =
     context.lookup("java:comp/env/EmployeeBean");
 // Narrow the reference to an EmployeeHome.
 EmployeeHome home =
     (EmployeeHome) PortableRemoteObject.narrow(homeObject,
                                                EmployeeHome.class);
 // Create a new record and narrow the reference.
 Employee rec =
     (Employee) PortableRemoteObject.narrow(home.create(empNo,
                                                        empName,
                                                        salary),
                                            Employee.class);
 // call method on the EJB
 rec.doSomething();
 ...
}

Note that we are not passing a hash table when creating a context in the line:

Context context = new InitialContext();

This is because the context is created with values read from the jndi.properties file, which in this example contains:

java.naming.factory.initial=com.evermind.server.ApplicationClientInitialContextFactory
java.naming.provider.url=ormi://localhost/bmpapp
java.naming.security.principal=SCOTT
java.naming.security.credentials=TIGER

Alternatively, you can pass a hash table to the constructor of InitialContext instead of supplying a jndi.properties file. The code looks like this:

Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.evermind.server.ApplicationClientInitialContextFactory");
env.put("java.naming.factory.initial",
"com.evermind.server.ApplicationClientInitialContextFactory");
env.put("java.naming.provider.url","ormi://localhost/bmpapp");
env.put("java.naming.security.principal","SCOTT");
env.put("java.naming.security.credentials","TIGER");
Context initial = new InitialContext(env);

Because the application client code refers to the EmployeeBean EJB, you must declare this in the <ejb-ref> element in the application-client.xml file:

<application-client>
   <display-name>EmployeeBean</display-name>
   <ejb-ref>
       <ejb-ref-name>EmployeeBean</ejb-ref-name>
       <ejb-ref-type>Entity</ejb-ref-type>
       <home>bmpapp.EmployeeHome</home>
       <remote>bmpapp.Employee</remote>
   </ejb-ref>
</application-client>

Recall that the EmployeeBean EJB is bound to the JNDI location java:comp/env/bmpapp/EmployeeBean as configured in the orion-ejb-jar.xml file. You must map the EJB name used in the application client program to the JNDI location where the EJB is actually bound to. You must do this in the orion-application-client.xml file:

orion-application-client.xml file:
<orion-application-client>
   <ejb-ref-mapping name="EmployeeBean" location="bmpapp/EmployeeBean" />
</orion-application-client>

From J2EE Application Components

You can use initial context factories in OC4J to access the following objects from J2EE application components:

Objects in the Same Application

You can use J2EE application components to access objects in the same application from servlets, JSP pages, and EJBs.

When code is running in a server, it is, by definition, part of an application. Because the code is part of an application, OC4J can establish defaults for properties that JNDI uses. Application code does not need to provide any property values when constructing a JNDI InitialContext object.

When this context factory is being used, the ApplicationContext is specific to the current application, so all the references specified in files such as web.xml, orion-web.xml, or ejb-jar.xml for that application are available. This means that a lookup using java:comp/env works for any resource that the application has specified. Lookups using this factory are performed locally in the same Java virtual machine (JVM).

If your application must look up a remote reference, such as a resource in another J2EE application in the same JVM or a resource external to any J2EE application, then you must use RMIInitialContextFactory or IIOPInitialContextFactory. See "Objects Not in the Same Application".

Example

As a concrete example, consider a servlet that must retrieve a data source to perform a JDBC operation on a database.

Specify data source location in data-sources.xml as follows:

<data-source
    class="oracle.jdbc.pool.OracleConnectionCacheImpl"
    location="jdbc/pool/OracleCache"
    username="hr"
    password="hr"
    url="jdbc:oracle:thin:@//<hostname>:<TTC port>/<DB ID>"
/>

For more information on data source locations, see Chapter 4, "Data Sources".

The servlet web.xml file defines the following resource:

<resource-ref>
   <description>
      A data source for the database in which
      the EmployeeService enterprise bean will
      record a log of all transactions.
   </description>
   <res-ref-name>jdbc/EmployeeAppDB</res-ref-name>
   <res-type>javax.sql.DataSource</res-type>
   <res-auth>Container</res-auth>
   <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

The corresponding orion-web.xml mapping is:

<resource-ref-mapping name="jdbc/EmployeeAppDB" location="jdbc/pool/OracleCache" />

The name value is the same as that specified in the <res-ref-name> element in web.xml. The location value is the location or ejb-location in the <data-source> element of data-sources.xml.

In this case, the following code in the servlet returns the correct reference to the data source object:

...
try {
  InitialContext ic = new InitialContext();
  ds = (DataSource) ic.lookup("java:comp/env/jdbc/EmployeeAppDB");
  ...
}
catch (NamingException ne) {
  throw new ServletException(ne);
}
...

No initial context factory specification is necessary, because OC4J sets ApplicationInitialContextFactory as the default value of the system property java.naming.factory.initial when the application starts.

There is no need to supply a provider URL in this case, because no URL is required to look up an object contained within the same application or under java:comp/.


Note:

Some versions of the JDK on some platforms automatically set the system property java.naming.factory.url.pkgs to include com.sun.java.*. Check this property and remove com.sun.java.* if it is present.

An application can use the java:comp/env mechanism to look up resources that are specified not only in its own name space, but also in the name spaces of any declared parent applications, or in the global application (which is the default parent if no specific parent application was declared).

Objects Not in the Same Application

Use one of the following context factories to access objects not in the same application:

RMIInitialContextFactory

For most application purposes, you can use either the default server-side ApplicationInitialContextFactory or the ApplicationClientInitialContextFactory. In some cases, however, you must use an additional context factory:

  • If your client application does not have an application-client.xml file, then you must use the RMIInitialContextFactory property and not the ApplicationClientInitialContextFactory property.

  • If your client application accesses the JNDI name space remotely—not in the context of a specific application—then you must use RMIInitialContextFactory.

The RMIInitialContextFactory uses the following environment properties, which ApplicationClientInitialContextFactory also uses. Table 2-2 lists these properties.

  • java.naming.provider.url

  • http.tunnel.path

  • Context.SECURITY_PRINCIPAL

  • Context.SECURITY_CREDENTIALS

Here is an example of a servlet that accesses an EJB running on another OC4J instance on a different machine. The EJB in this example is the EmployeeBean that is used in the "Accessing Objects from an Application Client".

Here is an excerpt of the servlet code:

Hashtable env = new Hashtable();
env.put("java.naming.factory.initial",
"com.evermind.server.rmi.RMIInitialContextFactory");
env.put("java.naming.provider.url","ormi://remotehost/bmpapp");
env.put("java.naming.security.principal","SCOTT");
env.put("java.naming.security.credentials","TIGER");
Context context = new InitialContext(env);
Object homeObject =
context.lookup("java:comp/env/EmployeeBean");

As in the case of the application client, you must declare <ejb-ref> elements in the web.xml file for this servlet:

<ejb-ref>
<ejb-ref-name>EmployeeBean</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<home>bmpapp.EmployeeHome</home>
<remote>bmpapp.Employee</remote>
</ejb-ref>

In addition, orion-web.xml, must include a mapping from the logical name EmployeeBean to the actual JNDI name where the EJB is bound, as shown in the following example:

<ejb-ref-mapping name="EmployeeBean" location="bmpapp/EmployeeBean" />
IIOPInitialContextFactory

The conditions under which to use this factory are the same as those for RMIInitialContextFactory except that the protocol being used is IIOP instead of ORMI.


Note:

You can use this factory only for looking up EJBs.

JNDI State Replication

JNDI state replication ensures that changes made to the context on one OC4J instance of an OC4J cluster is replicated to the name space of every other OC4J instance.

When JNDI state replication is enabled, you can bind a serializable value into an application context (using a remote client, EJB, or servlet) on one server and read it on another server. You can also create and destroy subcontexts in this way.

This section explains:

Enabling JNDI State Replication

JNDI state replication is enabled when EJB clustering is enabled.

To take advantage of JNDI state replication, you must enable EJB clustering, even if you do not specifically require EJB clustering (for example, when using JNDI to find startup classes or data sources).

For information on enabling EJB clustering, see the EJB clustering chapter in the Oracle Application Server Containers for J2EE Enterprise JavaBeans Developer's Guide.

For information on OC4J clustering in general, see the clustering chapter in the Oracle Application Server Containers for J2EE User's Guide.

JNDI State Replication Limitations

Consider the following limitations when relying on JNDI state replication:

Multiple Islands on a Given Subnet

Although OC4J processes can be organized into groups (known as islands) to improve state-replication performance, EJB applications replicate state between all OC4J processes in the OC4J instance and do not use the island subgrouping. This is described in the clustering chapter in the Oracle Application Server Containers for J2EE User's Guide.

Consequently, JNDI clustering is not limited to an island subnet. If there are multiple islands on a single subnet, then all islands on that subnet share the global JNDI context.

Propagating Changes Across the Cluster

Rebinding (renaming) and unbinding are not propagated: they apply locally but are not shared across the cluster.

Bindings to values that are not serializable are also not propagated across the cluster.

Binding a Remote Object

If you bind a remote object (typically a home or EJB object) in an application context, then that JNDI object is shared across the cluster but there is a single point of failure if the first server it is bound to fails.

JNDI Lookups in a Multiple-Instance Environment

In an environment with multiple OC4J instances, JNDI lookups require additional information:

  • opmn prefix

  • ons host name

  • ons port number

This applies to EJBs and JMS, as well.