Chapter 14. Locating Named Services through JNDI

An Introduction to the Java Naming and Directory Interface

The Java Naming and Directory Interface (JNDI) provides the interface to a naming and directory service for Java applications including J2EE technology. It is extremely important to understand that JNDI does not provide the specification for the actual naming service; rather, it provides an independent, neutral and unified interface to the provider of the actual naming service. Its purpose, as used by J2EE, is to enable Java applications to locate remote objects on the network. The semantics of a naming service are very much like those of a hash table, where a unique name is paired with an object. The binding between the name and object is stored persistently by the service provider being accessed through JNDI. Examples of JNDI service providers include the Lightweight Directory Access Protocol (LDAP) server, Domain Naming Service (DNS), Network Information Service (NIS) and the RMI Registry.

The naming service provider allows the object to be retrieved by simply looking up its JNDI name, which is set by the object’s deployer in the deployment descriptor. The naming service is an integral part of all distributed processing middleware implementing RMI, CORBA or J2EE technologies. With any of these technologies, the typical scenario for a client to use a remote object is as follows:

  1. The remote interface must be registered with the naming service.

  2. The client uses JNDI to look up the registered name in the naming service and retrieve the remote object that is bound to that name.

  3. The return value is an object that implements the remote interface.

  4. The client uses the remote interface to communicate with the remote object.

The JNDI Architectural Framework

As illustrated in Figure 14.1, JNDI provides two interfaces between a Java application and a naming or directory service, as follows:

The JNDI architectural framework provides a common API to a variety of naming and directory services.

Figure 14.1. The JNDI architectural framework provides a common API to a variety of naming and directory services.

  • The Application Programming Interface (API) can be used by a developer to access a naming or directory service from within a client application.

  • The Service Provider Interface (SPI) provides the capability for a J2EE Server to be independent of any specific industry naming or directory service provider. The SPI is plugged into the JNDI framework and provides a mapping from the JNDI API to the naming or directory service provider. Access to the service provider from the JNDI API is provided via a naming manager, which is typically provided by the J2EE server implementing the JNDI service, as in the case of WebLogic Server.

Note

Further descriptions of the JNDI APIs and SPIs are provided in their respective sections later in this chapter.

Hence, the JNDI architecture is independent of any specific service provider and therefore supports access to a variety of existing and emerging naming and directory services.

The Java 2 SDK version 1.3 and later releases include the JNDI classes and the three Service Provider Interfaces—LDAP, COS, and RMI—shown in Figure 14.1. JNDI is also available as a Java Standard Extension for use with JDK 1.1 and Java 2 SDK 1.2. WebLogic Server includes these three standard SPIs, as well as the WebLogic SPI for WebLogic Server’s embedded naming service.

The four Service Provider Interfaces included in WebLogic Server are:

  • LDAP SPI—The Service Provider Interface for an LDAP server

  • COS SPI—The Service Provider Interface for the Common Object Services used by CORBA

  • RMI SPI—The Service Provider Interface used by RMI to contact the rmiregistry

  • WebLogic SPI—The implemented Service Provider Interface to make its services available through JNDI

Additional Service Provider Interfaces for JNDI are also available, including Domain Name Service (DNS) and Network Information Service (NIS).

Note

A complete list of JNDI complaint service providers can be located at http://java.sun.com/products/jndi/serviceproviders.html.

Understanding Naming and Directory Services

To use JNDI, you need to have a basic understanding of what naming and directory services are. A naming service is a repository to store the bindings between a name and an object.

Note

The association of a name to an object in a naming or directory service is called a binding.

A directory service extends this capability by allowing the bindings to also contain a list of attributes. JNDI provides the ability to lookup the name of a bound object or search for bound objects by matching attributes that are stored with the object.

Note

WebLogic Server is strictly used as a naming service to lookup names that are bound to an object in the JNDI tree; no directory service attributes are used.

A computer file system can be thought of as a naming service. You provide the filename, and it returns the data stored with that file. This is directly analogous to what is offered by a naming service. For J2EE applications, the unique JNDI name is bound to the interface for the remote object. The administration of the naming service is performed through the JNDI API or tools provided by the J2EE server implementing the naming service. For example, WebLogic Server provides access to its naming service through the Administrator Console.

The following sections describe the naming and directory services supported by WebLogic Server through the provided SPIs.

LDAP Server

LDAP stands for the Lightweight Directory Access Protocol which provides both a naming and a directory service. LDAP evolved from the X.500 Directory Access Protocol, where it originally only provided the TCP/IP front end for DAP. The X.500 DAP is based on the OSI model for networking. LDAP provided the interface to TCP/IP clients. Gradually, LDAP and DAP merged into the standalone entity now known simply as LDAP which is considered a “lightweight” implementation of the Directory Access Protocol.

LDAP now runs as a standalone service. It must be configured with a back-end database that is used for persistent storage of the bindings and attributes. The schema of the database is organized as a hierarchical tree structure, also commonly referred to as the Directory Information Tree (DIT). Each element in the tree has a unique name, called its distinguished name. The distinguished name is constructed by concatenating the name of each element up to the root of the tree. An example of the LDAP tree structure is shown in Figure 14.2.

The LDAP tree structure is a graphical representation of the distinguished names.

Figure 14.2. The LDAP tree structure is a graphical representation of the distinguished names.

From the elements in Figure 14.2, you can see that the LDAP distinguished name for the RemoteObject is "cn=RemoteObject,dc=weblogic,dc=com". Each element of the distinguished name is a node in the tree. This example contains three elements separated by commas which follows the syntax of an LDAP distinguished name. Each element must match an attribute type that is defined in a schema that the LDAP server was configured to install.

The syntax for an individual element in the distinguished name is:

<attribute>=<name>

The <attribute> must match an attribute from the schema. The <name> is any name of your choosing to uniquely identify the entry.

Note

The specification for the LDAP schema used by Java can be found at http://www.ietf.org in RFC 2713 Schema for Representing Java Objects in an LDAP Directory. V. Ryan, S. Seligman, R. Lee. October 1999.

The configuration of the LDAP server specifies a base distinguished name in the hierarchical tree for each back-end database that it is configured to use. All elements below the base are physically stored in the corresponding back-end database. The LDAP server configuration also defines a root distinguished name which is used to control access to the server. The root distinguished name is password protected.

Note

An example of how access is controlled by the root distinguished name is provided in the “LDAP Security Considerations” section later in this chapter.

Because LDAP is a directory service, each element in the tree may have a list of attributes. Again, the attributes must match the schema that is defined for the LDAP server. In the case of J2EE applications, the JNDI name is bound to a serialized Java object that represents the remote interface; no directory attributes are used.

Note

LDAP has become the standard for network directory services.

WebLogic Server is compatible with any LDAP server that is LDAP v2 compliant. For example, the following LDAP servers have been tested with WebLogic:

  • Sun’s iPlanet version 4.1.3

  • Microsoft Active Directory as shipped with Windows 2000

  • Open LDAP version 2.0.7

  • Novell NDS version 8.5.1

RMI Registry

The RMI registry is the naming service used by Java Remote Method Invocation. It maintains the bindings between a name and the object that implements the remote interface. The RMI registry is accessed from RMI clients using the JNDI API or the java.rmi.Naming class.

Note

Refer to the section “Using the RMI SPI” later in this chapter for further information on accessing the RMI registry through JNDI.

The entries in the RMI registry are created by the RMI remote object which binds the name to the remote object that it is implementing. The RMI client looks up the name in the RMI registry to retrieve the remote interface. The Java 2 Standard Edition includes the executable “rmiregistry” that implements the registry for RMI.

Note

▸ For further information on RMI, see Chapter 12, “Distributed Processing Using RMI,” p. 385.

COS Name Server

The Common Object Services (COS) Name Server is the naming service for CORBA. It maintains the bindings between a name and a CORBA server. The COS Name Server is accessed using the JNDI API or the classes in the org.omg. CosNaming.NamingContext package. Listing 14.1 shows an example of locating a CORBA server named “Hello” using the classes in the org.omg.CosNaming and org.omg.CosNaming.NamingContextPackage packages.

Example 14.1. The Hello CORBA Server Is Located Using the COS Naming Context Classes

import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;

// get a reference to the Hello server from CORBA
public void findHelloServer()
{
  org.omg.CORBA.Object objRef =
    orb.resolve_initial_references("NameService");
  NamingContext ncRef = NamingContextHelper.narrow(objRef);

  // resolve the Object Reference in Naming
  NameComponent nc = new NameComponent("Hello", "");
  NameComponent path[] = {nc};
  Hello helloRef = helloHelper.narrow(ncRef.resolve(path));
}

The COS naming service can also be accessed using JNDI. The advantage of using JNDI is to better achieve portability. Rather than being locked into CORBA, writing the code using JNDI provides the flexibility to attach to a different naming service without significant modification to the code.

Note

Refer to the section “Using the COS SPI” later in this chapter for further information on accessing the COS name server using the JNDI API.

The WebLogic Naming Service

WebLogic Server’s implementation of a JNDI naming service serves as an in-memory repository and lookup service for all hosted J2EE objects and services, such as:

  • EJB Home stubs

  • JDBC DataSources and Connection Pools

  • JMS Destinations and Connection Factories, Queues and Topics

  • RMI Stubs

For example, in a J2EE application, a JavaServer Page (JSP) or servlet is typically the client of the Enterprise Java Bean (EJB); thus, it performs the lookup operation using JNDI to retrieve the client-side interface to the EJB. An entity EJB also uses JNDI to lookup the DataSource and UserTransaction objects to communicate with a database.

However, since the JNDI objects are stored in-memory, the JNDI service should not be used as a database. The objective of JNDI is to store Java objects to support repetitive lookups only. Storing large objects, such as a file, using JNDI would not only require a large amount of memory, but would also be a burden on the network.

Note

Refer to the section “Examples of Using JNDI in J2EE Applications” later in this chapter to see specific examples of accessing the WebLogic Naming Service using JNDI.

The Structure of the WebLogic Naming Service—The JNDI Tree

In order to bind and lookup objects using JNDI in WebLogic Server, you must understand the internal structure of WebLogic Server’s naming service, also referred to as the JNDI tree.

The structure of the WebLogic JNDI tree is illustrated in Figure 14.3, where:

The Internal Structure of the WebLogic Server’s JNDI Tree.

Figure 14.3. The Internal Structure of the WebLogic Server’s JNDI Tree.

  • A Context (C) represents a node in the tree and is bound to other contexts or objects. A context bound to another context is known as a subcontext. For example, given a DNS domain Bea.COM, the DNS domain Bea is a subcontext of COM.

  • Objects (O) are bound to a context and represent the leaves in a JNDI tree. Examples of objects include EJB Home interface objects, DataSource objects and factory objects for creating connections to JMS topics. A binding associates an object with a name with its relative context. Hence, each Context can be asked to find an object within its branch of the tree by giving the object’s name relative to its context.

  • The Root Context (RC) is the uppermost context of the JNDI tree.

  • The Initial Context (IC) serves as the starting point for all future JNDI tree searches (object lookups), similar to when you select your current directory on a file system.

The WebLogic Server binds J2EE services into the JNDI tree as part of the installation. In addition, the WebLogic container binds the local and remote home interfaces of EJBs into the JNDI tree when enterprise applications are deployed. The installed J2EE services can be viewed on the WebLogic Administrator Console using the following steps:

  1. Connect to the WebLogic Administrator Console with a web browser. If the web browser is being run on the same system as the WebLogic Application Server, the URL is typically http://localhost:7001/console.

  2. The frame on the left side is the navigation tree to select the available services. In the navigation tree, open the Servers folder in the domain that is installed. This folder contains the list of configured servers. Right-click on a server name and select the “View JNDI tree” menu item.

  3. The JNDI tree for the selected server opens in a new browser window. An example of the JNDI tree viewer is shown in Figure 14.4, which shows the default JNDI bind names and objects under the weblogic context.

    The bind names and objects in the JNDI tree can be viewed from the WebLogic Administrator Console.

    Figure 14.4. The bind names and objects in the JNDI tree can be viewed from the WebLogic Administrator Console.

You can also use the WebLogic.Admin utility to view the JNDI bindings in your WebLogic Server using the following syntax:

java weblogic.Admin [-url URL] -username username -password password LIST context

where:

  • URL specifies the listen address of the WebLogic Server that is the target of the command. The format for the URL is hostname:port; for example the default is localhost:7001.

  • username specifies the username to access the target WebLogic Server for the command.

  • password specifies the password associated with the username to access the target WebLogic Server for the command.

  • LIST specifies the command to list the JNDI tree node bindings.

  • context specifies the JNDI context for lookup, for example, weblogic, weblogic.ejb, or javax.

For example, in the following weblogic.Admin statement, the user wls, who has a password of einstein, requests a list of the node bindings in the context named weblogic:

java weblogic.Admin -url localhost:7001 -username wls -password einstein LIST weblogic

The output for this statement is shown in Figure 14.5.

Using the weblogic.Admin utility to view the WebLogic JNDI bindings.

Figure 14.5. Using the weblogic.Admin utility to view the WebLogic JNDI bindings.

Tip

If a JNDI lookup fails, you can use the WebLogic Administrator Console to “View the JNDI tree” and verify that the attributes of the bound object match the name you are trying to lookup.

Using JNDI in a WebLogic Server Cluster

A unique capability of the WebLogic naming service is that it can provide support for a WebLogic clustered environment. In a clustered environment, multiple WebLogic Servers work together to provide a seamless, fault-tolerant application server to the J2EE clients. Each WebLogic Server in the cluster shares information about its services with the other WebLogic Servers. From this collection of information, a clusterwide JNDI tree of services is created. A JNDI lookup operation with the WebLogic naming service can locate all the services available to the cluster, not just an individual application server. WebLogic clusters are supported by a replicated clusterwide JNDI tree that provides access to both replicated and pinned RMI and EJB objects.

The provision of the WebLogic naming service to support clustered capabilities enables it to offer services to J2EE applications that other naming services cannot support. Specifically, JNDI names are bound to objects in the WebLogic naming service that are used with the Enterprise Java Beans, RMI, JDBC, and JMS technologies. Therefore, it is important to understand the implications of binding an object to the JNDI tree in a clustered environment to use the WebLogic naming service effectively.

A WebLogic Server cluster provides multiple, cooperating WebLogic Servers that share common services. This configuration enables load-balancing and failover of the execution of J2EE services. Load-balancing spreads the execution over the available hardware resources. Failover provides robustness and fault tolerance by automatically identifying when a server is not operational, and choosing a different application server for the next instance of the remote object or the next invocation of an existing remote object. The capability to offer load-balancing and failover is possible because the objects that are bound in JNDI are automatically replicated throughout the cluster to create a common JNDI tree. The definition of replicated versus pinned objects is whether or not the object can participate in load-balancing and failover. Replicated objects are allowed to participate in load-balancing an failover because they can exist on any application server in the WebLogic cluster. Pinned objects have an application specific need to exist on only one server, and therefore cannot be replicated to another server in the cluster. Replicated objects are preferred in order to take advantage of the robustness and scalability of the WebLogic cluster.

There are, however, application-specific reasons for not allowing the replication of various J2EE services. The first issue deals with EJB session beans. If a bean is stateful, it may store client state information on the application server. To maintain state, the EJB session bean must always execute on the same application server. This concept is referred to as a pinned object meaning the object is pinned to a specific application server. The alternative is referred to as a replicated object which exists on multiple servers in the cluster. Though the terminology is not as explicit as stateful or stateless, an RMI remote object may also store state information and therefore must also be bound as a pinned object.

The JNDI Service Provider Interface

The JNDI architecture supports pluggable modules referred to as Service Provider Interfaces (SPIs), as illustrated earlier in Figure 14.1. They are responsible for implementing the client-side protocol for a specific naming service. JNDI provides a common API to the client independent of the selected SPI.

The Java application chooses which JNDI SPI it wants to use through the javax.naming.Context interface. Each SPI implements an InitialContextFactory that creates an instance of an object that implements the Context interface. The context factory is responsible for creating an instance of a JNDI Context for its particular protocol. A hash table is passed to the InitialContextFactory that contains properties used to customize the SPI. This hash table is referred to as the JNDI context environment. The javax.naming.Context interface defines constants that are used as the key value of the hash table, as listed in Table 14.1.

Table 14.1. The Context Environment Defines Property Names for Configuring the Hashtable

Property

Comment

Context.INITIAL_CONTEXT_FACTORY

Specifies the class name that is being used for the SPI context factory.

Context.PROVIDER_URL

Specifies the URL of the service provider. The format of the URL is protocol://hostname:port

Context.SECURITY_AUTHENTICATION

Specifies the security level to use. It may be set to one of “none”, “simple”, or “strong”. If the level is unspecified, the behavior is set by the SPI.

Context.SECURITY_PRINCIPAL

Specifies the name of the user who has authentication privileges on the server.

Context.SECURITY_CREDENTIALS

Specifies the password for the user specified by the SECURITY_PRINCIPAL property. This property may also be used to pass an object that implements secure user information that is service provider specific.

Note

The WebLogic JNDI allows the SECURITY_CREDENTIAL to be passed as an object that implements the weblogic.security.acl.UserInfo interface which is the weblogic.security.acl.DefaultUserInfoImpl class. However, this has been deprecated by the WebLogic 7.0 rules-based LDAP Authentication Provider in the Pluggable Security Infrastructure. The recommended security is provided by the Java Authentication and Authorizaton Service (JAAS). Refer to the “LDAP Security Considerations” later in this chapter for further information.

Examples of using the LDAP, RMI, COS, and WebLogic SPIs are discussed in the following sections.

Using the LDAP SPI

The InitialContextFactory class for the LDAP SPI is com.sun.jndi.ldap.LdapCtxFactory. The PROVIDER_URL is constructed with a protocol, hostname, and port. The protocol is ldap, and the hostname is the name of the host where the LDAP server is running. If the LDAP server is running on the same system as the Java application, you can use localhost as the hostname. The default port for LDAP is 389, but the LDAP server may be running on another port. A sample PROVIDER_URL for LDAP is

ldap://localhost:389

The example in Listing 14.2 creates a javax.naming.Context for the LDAP SPI. The context environment specifies com.sun.jndi.ldap.LdapCtxFactory as the InitialContextFactory. The PROVIDER_URL defines the hostname and port of the LDAP server. The SECURITY_AUTHENTICATION, SECURITY_PRINCIPAL, and SECURITY_CREDENTIALS are used to authorize access to the root distinguished node of the LDAP database.

Note

See the next section, “LDAP Security Considerations,” for further information on LDAP security.

Example 14.2. The JNDI SPI Is Configured Through the LdapCtxFactory for LDAP

/** Create JNDI Context for LDAP
    @param    rootDN    LDAP root distinguished name
    @param rootPW    LDAP root password
    @returns JNDI Context
    @exception NamingException
*/
private Context createLdapContext(
    String rootDN,
    String rootPW )
    throws NamingException
{
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
    env.put( Context.PROVIDER_URL, "ldap://localhost:389" );
    env.put( Context.SECURITY_AUTHENTICATION, "simple" );
    env.put( Context.SECURITY_PRINCIPAL, rootDN );
    env.put( Context.SECURITY_CREDENTIALS, rootPW );
    Context ctx = new InitialContext( env );
    return ctx;
}

LDAP Security Considerations

LDAP security properties are determined by the configuration of the LDAP server. Typically, no security credentials are required for lookup or search operations. To protect the contents of the LDAP server, security is enforced for bind, rebind, and unbind operations. If the LDAP server is configured with simple clear-text passwords, set the SECURITY_PRINCIPAL to the root-distinguished name, and set the SECURITY_CREDENTIALS to the root password. Listing 14.2 provided an example using the root distinguished name with a root password.

In addition to simple text passwords, the WebLogic server provides the capability to configure an LDAP Authentication Provider containing users and groups. This is configured through the Security Realms on the WebLogic Administrator Console. From the configuration of a security realm, the LDAP Authentication Provider is selected and configured. The WebLogic LDAP Authentication provides a fully compatible Java Authentication and Authorization Service (JAAS). A working JAAS sample is provided with the WebLogic Server software. The sample is located in the SAMPLES_HOMEserversrcexamplessecurityjaas directory provided with WebLogic Server.

Note

▸ For further information on security see Chapter 26, “Managing the WebLogic Security Service,” p. 889.

Using the RMI SPI

The InitialContextFactory class for the RMI SPI is com.sun.jndi.rmi.registry.RegistryContextFactory. The PROVIDER_URL is constructed with a protocol, hostname, and port. The protocol is rmi, and the hostname is the name of the host where the rmiregistry is running. If the rmiregistry is running on the same system as the Java application, you can use localhost as the hostname. The default port for RMI is 1099, but the rmiregistry may be running on another port. A sample PROVIDER_URL for RMI is

rmi://localhost:1099

The example in Listing 14.3 creates a javax.naming.Context for the RMI SPI. The context environment specifies com.sun.jndi.rmi_registry.RegistryContextFactory as the InitialContextFactory. The PROVIDER_URL defines the hostname and port of the RMI server. The context environment for RMI requires the RMISecurityManager to be specified.

Note

Refer to the next section, “RMI Security Considerations” for further information on RMI security.

Example 14.3. JNDI Context for RMI

/** Create JNDI Context for RMI
    @returns JNDI Context
    @exception NamingException
*/
private Context createRmiContext()
    throws NamingException
{
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.rmi.registry.RegistryContextFactory" );
    env.put( Context.PROVIDER_URL, "rmi://localhost:1099" );
    env.put( "java.naming.rmi.security.manager", "RMISecurityManager" );
    Context ctx = new InitialContext( env );
    return ctx;
}

RMI Security Considerations

RMI requires that you install a security manager to load objects from a remote server. The RMI SPI uses the java.naming.rmi.security.manager property to indicate that it should attempt to install the RMISecurityManager. This property can be set to any value to request that the security manager be installed.

Using the COS SPI

The InitialContextFactory class for the COS SPI is com.sun.jndi.cosnaming.CNCtxFactory. The PROVIDER_URL for the Common Object Services is slightly more complex than the other Service Provider Interfaces. The URL is constructed with a protocol, hostname, port, and the name of the CosNaming service. For COS, the URL is used to configure the root-naming context and/or the Object Request Broker (ORB). The protocol can be either iiop or iiopname. The iiop protocol specifies a single hostname, and the iiopname protocol specifies an addr_list, which is a list of hostnames. The default port for iiop is 900, and the default port for iiopname is 9999. Examples of the two forms for the PROVIDER_URL are:

iiop://localhost:900/<cosnaming_name>
iiopname://<addr_list>:9999/<cosnaming_name>

The example in Listing 14.4 creates a javax.naming.Context for the COS SPI. The context environment specifies com.sun.jndi.cosnaming.CNContextFactory as the InitialContextFactory. The PROVIDER_URL defines the hostname and port of the CosNaming service. The COS SPI does not specify SECURITY_CREDENTIALS as it uses the Java Security Manager.

Note

Refer to the next section “COS Security Considerations” for further information on COS security.

Example 14.4. JNDI Context for COS

/** Create JNDI Context for COS
    @returns JNDI Context
    @exception NamingException
*/
private Context createCosContext()
    throws NamingException
{
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.cosnaming.CNCtxFactory" );
    env.put( Context.PROVIDER_URL, "iiop://localhost:900" );
    Context ctx = new InitialContext( env );
    return ctx;
}

COS Security Considerations

COS security is monitored by the installed security manager. This chapter specifically focuses on JNDI; details of the Java Security Manager are not covered in this chapter. However, as a brief overview, when a security manager has been installed, you must grant to the application using JNDI and the COS naming service provider the following permissions:

permission java.net.SocketPermission "host[:port]", "connect";

To grant permissions with the Java Security Manager, you add the permission entry to the file being administered by the java.security.policy property.

Using the WebLogic SPI

The InitialContextFactory class for the WebLogic SPI is weblogic.jndi.WLInitialContextFactory. The URL is constructed with a protocol, hostname, and port. The protocol is t3, and the hostname is the name of the host where WebLogic Server is running. If WebLogic Server is running on the same system as the Java application, you can use localhost as the hostname. The default port for the WebLogic name service is 7001, but it may be running on another port. A sample PROVIDER_URL for the WebLogic name service is

t3://localhost:7001

WebLogic Security Considerations

WebLogic security properties are determined by the WebLogic Server security realm. The SECURITY_PRINCIPAL property is used to specify a user for authentication purposes. The default user is "guest". The SECURITY_CREDENTIALS property is overloaded; the value can be either the password for the user or an object that implements the weblogic.security.acl.UserInfo interface. If a UserInfo object is passed, the PROVIDER_URL property is ignored.

Creating the Context Environment for WebLogic

The WebLogic SPI provides both the traditional context environment configuration using a Hashtable, as well as the WebLogic Environment class. The Environment class offers the convenience of a Java Bean API using set methods to configure the properties. This mechanism provides compile-time type checking of the parameters that cannot be done by the Hashtable. The default constructor for the Environment class initializes a set of default values. Table 14.2 shows the attributes of the Environment class with the corresponding default value. You do not need to set a value if the default matches your needs.

Table 14.2. The Environment Class Attributes That Control the Configuration of the Context Environment

Environment Attribute

Default Value

InitialContextFactory

WLInitialContextFactory

ProviderURL

"t3://localhost:7001"

SecurityPrincipal

"guest"

SecurityCredentials

"guest_password"

The example in Listing 14.5 shows the traditional Hashtable implementation. Listing 14.6 shows an example using the WebLogic Environment class to configure the context. Both examples perform identical initialization of the JNDI Context.

Example 14.5. JNDI Context for WebLogic: Traditional Hashtable Implementation

/** Create JNDI Context for WebLogic
    @param    user        User in WebLogic Server security realm
    @param password    Password for user
    @returns JNDI Context
    @exception NamingException
*/
private Context createWebLogicContext(
    String user,
    String password )
{
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory" );
    env.put( Context.PROVIDER_URL, "t3://localhost:7001" );
    env.put( Context.SECURITY_AUTHENTICATION, "simple" );
    env.put( Context.SECURITY_PRINCIPAL, user );
    env.put( Context.SECURITY_CREDENTIALS, password );
    Context ctx = new InitialContext( env );
    return ctx;
}

Example 14.6. JNDI Context for WebLogic: Using the Environment Object

/** Create JNDI Context for WebLogic
    @param  user        User in WebLogic Server security realm
    @param  password    Password for user
    @returns JNDI Context
    @exception NamingException
*/
private Context createWebLogicContext(
    String user,
    String password )
{
  try {
    // Create the WebLogic Environment
    // use default value: WLInitialContextFactory, "t3://localhost:7001,
    Environment env = new Environment();
    env.setSecurityPrincipal( user );
    env.setSecurityCredentials( password );
    // in this case, we get the InitialContext from the Environment object
    Context ctx = env.getInitialContext();
    // use ctx to lookup JNDI services
  } catch( NamingException x ) {
    System.err.println( x.toString() );
  }
}

The JNDI Application Programming Interface

The JNDI API is provided by the javax.naming.Context interface for naming services and javax.naming.directory.DirContext for directory services. J2EE applications rely exclusively on naming services; therefore, this introduction to the JNDI API focuses on the javax.naming.Context class. However, an overview of using JNDI with directory services is also provided to give a complete introduction to the JNDI API. The Java application creates and uses a javax.naming.Context object to lookup a name in the naming service. The return value is the object that was bound to that name.

Looking Up an Object Using the JNDI Context

After the context is created, the lookup() method is used to locate an object by name, errors are handled with exceptions. The NameNotFoundException is thrown if the name is not found in the naming service. The NamingException is thrown if there was a communication failure with the naming service. Listing 14.7 retrieves an EJB named MySessionBean from the Context created for WebLogic Server.

Example 14.7. Retrieving MySessionBean from the Context Created for WebLogic Server

try {
    // create the Context first...
    // use ctx to lookup an EJB named MySessionBean
    MySessionBean msb = (MySessionBean)ctx.lookup( "ejb.mySessionBean" );
    // use MySessionBean here
} catch( NameNotFoundException x ) {
    System.err.println( "ejb.mySessionBean was not found" );
} catch( NamingException x ) {
    System.err.println( x.toString() );
}

Closing the JNDI Context

It is important to close the Context after the client is finished using it. By doing so, you release the resources that were created for the Context. A finally block is recommended to ensure the Context is closed whether or not an exception is thrown. The structure of using the finally block to close the context is shown in Listing 14.8.

Example 14.8. Using the finally Block to Close the Context

Context ctx = null;
try {
    // create the Context
    ctx = new InitialContext();

    // use the Context

} catch( NamingException x ) {
    System.err.println( x.toString() );
} catch( Exception x ) {
    System.err.println( "unexpected exception: " + x );
} finally {
    try {
        if( ctx != null )
          ctx.close();
    } catch( Exception x ) {
        System.err.println( "failed to close Context: " + x );
    }
}

Binding an Object Using the JNDI Context

In this section, you learn how to bind an object with a JNDI naming service. The binding is created using the bind() or rebind() methods of the Context object.

Note

An Enterprise Java Bean does not contain code to explicitly bind the EJB with the naming service. The EJB Container in WebLogic Server is responsible for updating the JNDI tree when the bean is deployed. The JNDI name for the binding is defined in the deployment descriptor for the EJB.

Follow these steps to bind an object with a JNDI naming service:

  1. Choose a unique name for the object.

  2. Create the object.

  3. Create a Context for the selected service provider.

  4. To support clustering for WebLogic Server, decide if the object is pinned or replicated. The environment property for controlling replication in WebLogic Server is WLContext.REPLICATE_BINDINGS. The value for this property is set to either “true” or “false” as a java.lang.String.

  5. Handle exceptions.

The parameters to the Context method bind() are a name as a String and an object. You must use the rebind() method to force the new object to be bound to a name that already exists. You use the unbind() method to remove the binding from the service provider. The parameter to unbind() is the bound name. All JNDI Context methods throw NamingException to indicate that a failure occurred while trying to communicate with the naming service. Listing 14.9 shows an example of binding a pinned object with the WebLogic naming service.

Example 14.9. Binding a Pinned Object with WebLogic Server

private void pinObject( String name, Object obj ) {
  try {
    Hashtable env = new Hashtable();
    // pin the object
    env.put( WLContext.REPLICATE_BINDINGS, "false" );
    Context ctx = new InitialContext( env );
    // bind the object
    ctx.bind( name, obj );
  } catch( NamingException x )
    System.err.println( "Failed to bind " + name + ": " + x );
  }
}

Examples of Using JNDI in J2EE Applications

The EJB container in the application server is responsible for binding the EJB object with the naming service when the object is deployed. Therefore, the most common function of JNDI for J2EE clients is to look up the interface for a remote object. In the following examples, you can assume that the client is running on the same system as WebLogic Server. From this assumption, you construct the JNDI Context by simply using the default constructor for InitialContext. The default values for the environment apply under these conditions.

Looking Up the EJB Home Interface

The heart of a J2EE application is the EJB. The clients of the EJB use JNDI to look up the home interface. The home interface is then used to create an instance of the remote interface for the EJB. With EJB, the name to look up is the same as the name of the home interface class. Listing 14.10 shows an example of an EJB client using JNDI to look up the home interface.

Example 14.10. An EJB Client Using JNDI to Look Up the Home Interface

Context ctx = null;
try {
  ctx = new InitialContext();
  MyEjbHome home = null;
  Object homeObj = ctx.lookup("MyEjbHome");
  home = (MyEjbHome)javax.rmi.PortableRemoteObject.narrow(homeObj, MyEjbHome.class);
}
catch (NamingException e) {
  e.printStackTrace();
}
catch( NamingException x ) {
  System.err.println( x.toString() );
}

Looking Up JMS Connection Factories and Distributed Destinations

The configuration of JMS includes connection factories and distributed destinations, each of which have a JNDI name. The connection factories enable JMS clients to create JMS connections. The distributed destinations are the JMS Queues and Topics.

Note

▸ For further information on JMS see Chapter 15, “The Java Messaging Service (JMS),” p. 471.

Chapter 15 describes the details of JMS Queue Producer/Consumer and JMS Topic Producer/Consumer. Here, you see how to use JNDI to retrieve these services from the WebLogic naming service. The ConnectionFactory, Queue, and Topic are all retrieved by performing a JNDI lookup. The name of the default JMS connection factory is the full class name weblogic.jms.ConnectionFactory. The JNDI name for the Queue and Topic is manually administered through the WebLogic Server Console as part of the configuration for JMS. The client of the JMS Queue uses JNDI to look up the name, as shown in Listing 14.11.

Example 14.11. A JMS Queue Client Using JNDI to Look Up the Name

try {
Context ctx = new InitialContext();
QueueConnectionFactory qcf = (QueueConnectionFactory)ctx.lookup(
"weblogic.jms.ConnectionFactory" );
Queue queue = (Queue)ctx.lookup( "MyJmsQueue" );
QueueConnection qc = qcf.createQueueConnection();
// use the QueueConnection and message queue
    } catch( NamingException x ) {
        System.err.println( x.toString() );
    }

The JMS Topic Producer and Consumer use JNDI in a similar manner as the preceding Queue example, as shown in Listing 14.12.

Example 14.12. JMS Topic Producer and Consumer Using JNDI to Look Up the Name

try {
Context ctx = new InitialContext();
TopicConnectionFactory tcf = (TopicConnectionFactory)ctx.lookup(
"weblogic.jms.ConnectionFactory" );
Topic topic = (Topic)ctx.lookup( "MyJmsTopic" );
TopicConnection tc = qcf.createTopicConnection();
// use the QueueConnection and message queue
    } catch( NamingException x ) {
        System.err.println( x.toString() );
    }

Looking Up JDBC DataSources

Chapter 16, “Managing Java Transactions Using JTA,” describes the advantages of using JDBC DataSources over the DriverManager. With WebLogic Server, the DataSource is bound to the naming service using the WebLogic Administrator Console. The client of the DataSource uses JNDI to look up the name, as shown in Listing 14.13.

Example 14.13. A DataSource Client Using JNDI to Look Up the Name

try {
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup( "MyJDBCDataSource" );
Connection con = ds.getConnection( DATABASE_USER, DATABASE_PASSWORD );
    } catch( NamingException x ) {
        System.err.println( x.toString() );
    }

Looking Up JTA UserTransactions

The UserTransaction object is covered in Chapter 16. In this case, there is no manual administration of the JNDI name; it is simply the full class name, javax.transaction.UserTransaction. The client that performs distributed transactions uses JNDI to look up the UserTransaction object, as shown in Listing 14.14.

Example 14.14. A Client Performing Distributed Transaction Using JNDI to Look Up the UserTransaction Object

try {
    Context ctx = new InitialContext();
    UserTransaction tx =
        (UserTransaction)ctx.lookup( "javax.transaction.UserTransaction" );
    tx.begin();    // start transaction
    // locate DataSource, establish connection, execute operations, close connections
    tx.commit();    // commit transactions
} catch( Exception x ) {
    System.err.println( "error has occurred" );
    try {
        tx.rollback();
    } catch( javax.transaction.SystemException se ) { }
}

Summary

As shown in this chapter, the distributed architecture of J2EE requires a naming service for clients to be able to look up the remote object. In fact, all middleware implementations, including RMI, CORBA, and EJB, rely on a naming service or registry. The WebLogic Server Cluster has even stronger needs for a naming service to support replication and failover in a clustered environment. JNDI provides a simple API that enables the client to retrieve the remote object by simply looking up a name.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset