Skip Headers

Oracle Application Server Containers for J2EE Services Guide
10g (9.0.4)

Part Number B10326-01
Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table of Contents
Contents
Go To Index
Index

Go to previous page Go to next page

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.

Initial Context

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

When OC4J starts up, it constructs a JNDI initial context for each application by reading each of the application's configuration XML files that can contain resource references.


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.


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 application's JNDI tree. 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.

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, the initial context is created by OC4J when the server is started, using the default environment for that application. This constructor is the one that 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. The second form of the InitialContext constructor is normally used 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 that are required by JNDI. These properties, defined in the javax.naming.Context interface, are listed in Table 2-1.

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 "Application Client Example" for a code example that sets these properties and gets a new JNDI initial context.

Creating the Initial Context in OC4J

Application clients are defined in section 9.1 of the J2EE 1.3 specification as "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]."

JNDI initial contexts can be used in the following ways:

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:

In deciding which JNDI initial context factory to use, 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) being used by the client application. 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, but that is 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 done in client code, or it can be specified in the jndi.properties file that is part of the application's application-client.jar file that is 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 that are 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 have to be defined in deployment descriptors in order to be bound to an application's JNDI context.

Environment Properties

ApplicationClientInitialContextFactory reads the properties shown in Table 2-2 from the environment if the ORMI protocol is being used.

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" .

Multiple hosts (for failover) can be supplied 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's 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.

Application Client Example

This is an example of how to configure an application client to access an EJB running inside an OC4J instance in the same machine.

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, we can pass a hash table to the constructor of InitialContext instead of supplying a jndi.properties file. The code would look 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);

Since the application client code refers to the EmployeeBean EJB, this must be declared 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. The EJB name used in the application client program must be mapped to the JNDI location where the EJB is actually bound to. This is done 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

Initial context factories can be used in OC4J to access the following objects from J2EE application components:

Objects in the Same Application

To access objects in the same application from servlets, JSP pages, and EJB, you can use J2EE application components.

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 that are 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 virtual machine.

If your application must look up a remote reference, either a resource in another J2EE application in the same JVM or perhaps a resource external to any J2EE application, then you must use RMIInitialContextFactory or IIOPInitialContextFactory. Also 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.

The data source location is specified in data-sources.xml as:

<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's 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

You can access objects not in the same application using one of these context factories:

RMIInitialContextFactory

Using either the default server-side ApplicationInitialContextFactory or specifying ApplicationClientInitialContextFactory works for most application purposes. In some cases, however, an additional context factory must be used:

The RMIInitialContextFactory uses the same environment properties (described in detail in Table 2-2) used by ApplicationClientInitialContextFactory:

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 by the "Application Client Example".

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, <ejb-ref> elements must be declared 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>

Also, a mapping from the logical name EmployeeBean to the actual JNDI name where the EJB is bound must be provided in orion-web.xml:

<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 Clustering

JNDI clustering 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 clustering is enabled, you can bind a serializable value into an application context (via 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 Clustering

JNDI clustering is enabled when EJB clustering is enabled.

To take advantage of JNDI clustering, 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 Clustering Limitations

Consider the following limitations when relying on JNDI clustering:

Multiple Islands on a Given Subnet

As described in the clustering chapter in the Oracle Application Server Containers for J2EE User's Guide, 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 sub-grouping.

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

Propagating Changes Across the Cluster

Re-binding (re-naming) and unbinding are not propagated: they apply locally but are not shared across the cluster.

Bindings to values which 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, that JNDI object will be shared across the cluster but there will be a single point of failure if the first server it is bound to fails.


Go to previous page Go to next page
Oracle
Copyright © 1996, 2003 Oracle Corporation.

All Rights Reserved.
Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table of Contents
Contents
Go To Index
Index