BEA Logo BEA WebLogic Server Release 5.0

  Corporate Info  |  News  |  Solutions  |  Products  |  Partners  |  Services  |  Events  |  Download  |  How To Buy

Using WebLogic JNDI

I. Introduction
Overview of JNDI in the WebLogic Framework
WebLogic JNDI architecture

II. The WebLogic JNDI API
WebLogic JNDI API reference
Overview of the WebLogic JNDI API

III. Implementing with WebLogic JNDI
Using WebLogic JNDI from a client
Creating a Context
Properties that affect the context creation
Creating a Context using a Hashtable
Creating a Context using a WebLogic Environment object
Creating a Context from within a server-side object
Associating a principal with a thread
Delegating to another service provider
Looking up an object
Using JNDI in a distributed application environment
Making an object available by binding it to a name
Making an object transportable
IV. Setting up ACLs for JNDI in the WebLogic Realm

Other related documents
Installing WebLogic (non-Windows)
Installing WebLogic (Windows)
Writing a WebLogic client application
Writing a server-side application
Using WebLogic Server Clusters
Developers Guides
API Reference Manual
Code examples
Glossary

Overview of JNDI in the WebLogic Framework

In the enterprise, naming and directory services -- the ability of your application to locate an object or service that may be anywhere on the network -- play an important part in building a distributed application. Particularly in a clustered environment, where clients may connect arbitrarily to any machine, the environment must have a naming service that can be depended upon to locate any service object requested no matter its physical location.

JNDI is a standard Java interface for accessing distributed services and data by name. It provides a portable, unified interface for services that need naming and directory services. The JNDI specification was defined independently of any specific naming or directory service implementation, but a developer can use it to access different, multiple naming and directory services such as LDAP, NDS, and NIS (YP). The JNDI specification also includes a specification for a service provider interface (SPI) to provide access into such heterogeneous service providers.

WebLogic JNDI is a multitier implementation of the Java Naming and Directory Interface. Through WebLogic's implementation of the JNDI specification, introduced with version 3.0, a client can access any JNDI service provider that is accessible to the WebLogic Server. This effectively gives clients seamless access to enterprise services and data without any knowledge of physical location.

JNDI distinguishes between naming services and directory services:

  • A naming service provides a mechanism to name objects (bind) and retrieve objects by name (lookup).

  • A directory service is a naming service that also allows for attributes to be associated with each object and provides a way to retrieve an object based on its attributes rather than its name (search).

Currently there are JNDI implementations provided by JavaSoft for the NIS naming service and the LDAP directory service. WebLogic JNDI also implements a naming provider that allows clients to access WebLogic services.

This document assumes a basic understanding of naming and directory services and of the JNDI specification, which is available from JavaSoft. Included in this document is an overview and implementation guide for WebLogic's implementation of JNDI within the WebLogic framework.

Top

WebLogic JNDI architecture

WebLogic's implementation of JNDI supplies an SPI (Service Provider Interface) for access to all of WebLogic's services. The SPI includes methods to give clients access to the WebLogic name services, methods to make objects available in the WebLogic name system, and methods to retrieve objects from the WebLogic name system.

WebLogic clusters are supported by a replicated cluster-wide JNDI tree that provides access to both replicated and pinned RMI and EJB objects.

The integrated naming and directory services provided by WebLogic JNDI may be used by many other WebLogic services. WebLogic RMI, for example, can bind and access remote objects by both the standard RMI methods as well as by JNDI methods.

Top

The WebLogic JNDI API

WebLogic's implementation of JNDI is based on the JavaSoft JNDI 1.2 and SPI specifications, available from JavaSoft. This document assumes knowledge of the specification and the use of the JNDI javadocs from JavaSoft, available online at JavaSoft.

WebLogic JNDI API reference

Package weblogic.jndi

Class java.lang.Object
    Class weblogic.jndi.Environment
    Interface weblogic.jndi.WLContext
    Class weblogic.jndi.WLInitialContextFactory

Overview of the WebLogic JNDI API

The WLInitialContextFactory provides the public WebLogic API for accessing and using WebLogic's JNDI implementation. In general, the WLInitialContextFactory interface sets your InitialContext to use WebLogic JDNI services.

You use WebLogic JNDI services for two purposes:

  • To get access to named objects. First you obtain a Context, and then you use that Context to retrieve named objects. This document covers this in the section, Using WebLogic JNDI from a client. Note that "client" in this sense may mean any consumer of JNDI services.

  • To name and bind objects to make them available to others. In general, any client that has access to a name system can retrieve any object in it. To make objects available to clients of a name system, you bind the object to a name in the naming tree. You may also need to ensure that a bound object is transportable, that is, that it can pass freely between virtual machines (VMs). This document covers this in the section, Using JNDI in a distributed application environment.
The class weblogic.jndi.WLInitialContextFactory provides an entry point for a client into the WebLogic name space, and most likely you will pass a set of properties to that context with a standard Java Hashtable, or with WebLogic's Environment object, which supplies convenient defaults and has set() methods that offer compile-time type-safety. References to other JNDI interfaces in this document are to WebLogic's implementation of JNDI. You should also refer to the API reference materials available at JavaSoft's website for information on the standard JavaSoft spec.

Top

Implementing with WebLogic JNDI

Using WebLogic JNDI from a client
Creating a Context
Properties that affect the context creation
Creating a Context using a Hashtable
Creating a Context using a WebLogic Environment object
Creating a Context from within a server-side object
Delegating to another service provider
Looking up an object
Using JNDI in a distributed application environment
Making an object available by binding it to a name
Making an object transportable

Using WebLogic JNDI from a client

A client may access objects in the WebLogic framework by creating an InitialContext within the WebLogic name system, and then retrieving objects by name from within that system. The two basic operations are creating an initial context and looking up objects in the name space.

Creating a Context

weblogic.jndi.WLInitialContextFactory
weblogic.jndi.Environment

To access a JNDI service provider using WebLogic JNDI, you create an InitialContext and pass it a context factory, which creates the context for a certain provider. In the WebLogic case, you will use the WebLogic context factory, weblogic.jndi.WLInitialContextFactory, as an argument. Once the context is created, it provides client access to naming services within a naming system, through a WebLogic as name service provider. To create a WebLogic context from a client, you must minimally specify this factory as the initial context factory, and the URL of a WebLogic Server in the JNDI environment as properties passed to the constructor of the InitialContext.

There are two processes for creating an initial context. One uses a Hashtable for setting properties, and the other uses a WebLogic Environment object to pass properties to the initial context. Both methods require setting property values. We'll discuss the properties first, and then explain how those properties get set in two methods of creating a context:

Creating a context using a Hashtable
Creating a context using a WebLogic Environment object

We'll also show how to create a context for use with server-side objects that will operate exclusively within the same VM as the server:

Creating a context from within a server-side object

Properties that affect the context creation

You will need to set parameters to create a Context. The initial context factory uses the various properties to customize your InitialContext for a specific environment. You can set these properties either by using a Hashtable or by using the setXXX() methods associated with WebLogic Environment object.

These properties (name/value pairs) determine how the WLInitialContext factory creates the Context. Set them either using a Hashtable, or using setXXX() methods in the WebLogic Environment class:

  • java.naming.provider.url. Set the URL of the service provider with the property name java.naming.provider.url. (In the example, we use the constant Context.PROVIDER_URL for this property name.) This property value should specify the WebLogic Server that will provide the name service. Value defaults to t3://localhost:7001.

  • java.naming.provider.delegate.environment. Optionally, you can use another Hashtable to establish a second set of properties to be used to delegate to a remote Context, by setting a second Hashtable as the value for the property name java.naming.provider.delegate.environment. (In the example, we use the constant WLContext.DELEGATE_ENVIRONMENT for this property name.) This Hashtable contains all the name/value pairs needed to create a third-party Initial Context, so that the WebLogic Server specified in the java.naming.provider.url will act as a router to a third-party name service. Conceptually, the WebLogic Server creates an InitialContext using these properties and then provides the caller with a local context that delegates to this remote context. (If this property is specified, the following two security-related properties -- java.naming.security.principal and java.naming.security.credentials -- are ignored.)

  • java.naming.security.principal. (In the example, we use the constant Context.SECURITY_PRINCIPAL for this property name.) Set the value for this property name to specify the identity of the principal (user) for security purposes. Value defaults to "guest" unless the thread has already been associated with a principal. See Associating a principal with a thread.

  • java.naming.security.credentials. (In the example, we use the constant Context.SECURITY_CREDENTIALS for this property name.) Set the value for this property name to specify the password for the principal, or, alternatively, an Object that implements the weblogic.security.acl.UserInfo interface, with the property java.naming.security.credentials. If you pass a UserInfo object in this property, the property java.naming.security.principal is ignored. Value defaults to "guest" unless the thread has already been associated with a principal. See Associating a principal with a thread.

You can use the same properties on either a client or a server. If on the server, a local Context will be used. If on a client or another server, the Context will delegate to a remote Context running on the server specified by the java.naming.provider.url property.

The following code illustrates how to obtain an InitialContext for the WebLogic naming service, using the properties java.naming.factory.initial (for which we substitute the constant Context.INITIAL_CONTEXT_FACTORY) and java.naming.provider.url (for which we substitute the constant Context.PROVIDER_URL):

  Context ctx = null;
  Hashtable ht = new Hashtable();
  ht.put(Context.INITIAL_CONTEXT_FACTORY,
         "weblogic.jndi.WLInitialContextFactory");
  ht.put(Context.PROVIDER_URL,
         "t3://localhost:7001");

  try {
    ctx = new InitialContext(ht);
    // Use the context in your program
  }
  catch (NamingException e) {
    // a failure occurred
  }
  finally {
    try {ctx.close();}
    catch (Exception e) {
      // a failure occurred
    }
  }
  

Note that you should always close a context when you have finished working with it, just as you close database and client connections and other finite resources. We recommend that you do so in a finally{} block, and that you wrap your close() method in a try{} block. If you attempt to close a Context that was never instantiated because of some other error, your program will throw an Exception that you should catch and deal with.

If the code is written for an application (instead of an applet, which requires that you set properties explicitly), you can create the initial context simply by specifying the JNDI properties as system properties and using the default constructor, as in:

  try {
    Context ctx = new InitialContext();
  }
  catch (NamingException e) {
    // a failure occurred
  }
  finally {
    try {ctx.close();}
    catch (Exception e) {
      // a failure occurred
      }
  }

Note that this method of setting properties cannot be used in an applet, because of restrictions in the sandbox security model.

There are other WebLogic-specific properties that you set to configure security parameters and that affect how objects are bound into the cluster-wide JNDI tree. Note that objects may be replicated across the tree or "pinned" to a particular server for use from within the cluster. These properties are identified by constants in the weblogic.jndi.WLContext class. There is more on JNDI-related clustering issues in the Developers Guide Using WebLogic Clusters.

Creating a Context using a Hashtable

You can create an InitialContext with a Hashtable in which you have put several properties (name/value pairs) that are used during the creation of the Context.

Initially, you pass the Hashtable to the constructor for InitialContext; at that point, the property java.naming.factory.initial is used to choose how the initial Context will be created. (In these examples, we use the constants found in the Context class for all property names.) To use WebLogic JNDI, you must always set this property to weblogic.jndi.WLInitialContextFactory, which identifies the factory that will actually create your Context. This part of the creation of an InitialContext is invariable.

You set this property using the property name java.naming.factory.initial. Note that in this example, we use the constant Context.INITIAL_CONTEXT_FACTORY. This property (name/value pair) specifies the factory used for creating the context. To gain access to WebLogic naming services, you must specify this property as weblogic.jndi.WLInitialContextFactory.

This completes the first step in the creation of a Context, using the property java.naming.factory.initial, which you set to Associating a principal with a thread

Delegating to another service provider
Creating a Context from within a server-side object e="Courier New" size=-1>weblogic.jndi.WLInitialContext. Then the WLInitialContextFactory.getInitialContext() uses other Hashtable name/value pairs to complete the creation of the Context.

Creating a Context using a WebLogic Environment object

weblogic.jndi.Environment

The simplest way to create an initial context is by using a WebLogic Environment object. Although the Environment object is WebLogic-specific, it offers you two really nice advantages: a set of defaults, which cuts down on the code you have to write, and some convenience "setter" methods that provide compile-type type-safety.

The type-safety setXXX() methods can save you time both writing and debugging. Now that you understand all about properties that are passed to the initial context, you can see that setting up these properties requires a lot of typing, and, in the end, those property names and values are just Strings that you might have mistyped or misnamed. The Environment object reduces the chance you will make such mistakes.

Here are a list of properties that the Environment method supplies setXXX() methods for. These constants come from both the javax.naming.Context class, and from the weblogic.jndi.WLContext class, which supplies Context parameters for WebLogic-specific features associated with clustering and security.

Constant from Context Class Environment method
INITIAL_CONTEXT_FACTORY setInitialContextFactory(String)
PROVIDER_URL setProviderURL(String)
SECURITY_PRINCIPAL setSecurityPrincipal(Principal)
SECURITY_CREDENTIALS setSecurityCredential(Object)
SECURITY_PRINCIPAL
SECURITY_CREDENTIALS
setSecurityUser(UserInfo)

Constant from
WLContext Class
Environment method
SSL_ROOT_CA_FINGERPRINTS setSSLRootCAFingerprints(String)
SSL_SERVER_NAME setSSLServerName(String)
SSL_CLIENT_CERTIFICATE setSSLClientCertificate(InputStream[])
CREATE_INTERMEDIATE_CONTEXTS setCreateIntermediateContexts(boolean)
REPLICATE_BINDINGS setReplicateBindings(boolean)
PIN_TO_PRIMARY_SERVER setPinToPrimaryServer(boolean)

The Environment comes with a set of defaults:

  • If you do not set an initial context factory, the default is to use WLInitialContextFactory.
  • If you do not set a principal and password, the default is to use guest/guest unless the thread has already been associated with a principal. See Associating a principal with a thread.
  • If you do not set a server URL, the default is to use "t3://localhost:7001".

This means that if you want to set up an initial context with these defaults, you can just write:

  Environment env = new Environment();
  Context ctx = env.getInitialContext();

Or if, for example, you want to set just a server to a DNS name for client cluster access, you might write:

  Environment env = new Environment();
  env.setProviderURL("t3://myweblogiccluster.com:7001");
  Context ctx = env.getInitialContext();

Creating a context from within a server-side object

You may also need to create a Context from an object that is instantiated in the WebLogic Server's VM, like an EJB or RMI object. There are a couple of considerations for server-side use; you do not need to specify things like provider URL and user, because these are already known to the VM creating the context. Server-side contexts will, of course, run in the context of the server itself.

To create a context from within a server-side object, all you need to do is new InitialContext, for example:

  Context ctx = new InitialContext();

You do not need to specify a factory, or a provider URL; by default, the context will be created as a WebLogic context and will connect to the local naming service.

Associating a principal with a thread

In order to perform work that requires authentication or access control, you must associate a principal, or user, with the thread that will perform the work. To do so, create a context with the appropriate principal and credential property values as described in the sections above. To disassociate a principal with the thread, close the context.

When a thread is associated with a principal, that principal becomes the default for the thread. If any contexts are subsequently created without principal or credential properties, the principal associated with the thread will remain unchanged.

While it is technically possible to share a single context among multiple threads, passing a context to another thread does not associate the principal used in creating the context with the new thread. The only way to associate a principal with a new thread is to create a new context within that thread. In addition, a context can only be closed within the thread with which it was created. For these reasons, it is strongly suggested that all work performed with a given context be handled in the same thread.

A thread may be associated with only one principal at any given time. If multiple contexts are created within a single thread without closing any contexts, the thread will be associated with the principal used in the last context created. principal information is stored with the thread in a stack. If the last context is closed, the thread becomes associated with the principal used in creating previous context, and so on.

Delegating to another service provider

Using WebLogic to support your calls to a delegate service provider provides several advantages:

  • The client doesn't need to install the delegate service provider.
  • The client doesn't need access to the delegate service provider.

To use another JNDI provider, you must provide a third property that specifies the property list to be used for connecting to the provider from the WebLogic Server. The following code illustrates this by creating an InitialDirContext that uses the WebLogic Server as an intermediate for accessing an LDAP directory service at bigfoot.com.

  DirContext bigfootDirCtx = null;
  Hashtable delegateHT = new Hashtable();
  // Use the LDAP provider that provided by Sun
  // to create a properties object for use with
  // a remote provider
  delegateHT.put(Context.INITIAL_CONTEXT_FACTORY,
                 "sun.jndi.ldap.LdapCtxFactory");
  delegateHT.put(Context.PROVIDER_URL,
                 "ldap://ldap.bigfoot.com:389");

  Hashtable ht = new Hashtable();
  ht.put(Context.INITIAL_CONTEXT_FACTORY,
         "weblogic.jndi.WLInitialContextFactory");
  ht.put(Context.PROVIDER_URL,
         "t3://localhost:7001");
  // Pass the server properties as the value this property
  ht.put(WLContext.DELEGATE_ENVIRONMENT, delegateHT);
  ht.put(Context.SECURITY_CREDENTIALS,   myUserInfo);

  try {
    bigfootDirCtx = new InitialDirContext(ht);
    // Do some work with this context
  }
  catch (NamingException e) {
    // a failure occurred
  }
  finally {
    try {bigfootDirCtx.close();}
    catch (Exception e) {
      // a failure occurred
    }
  }

Note that the purpose of WebLogic JNDI in this case is to allow the client to access a directory service that it may not otherwise be able to access (because of security restrictions).

When delegating to another service provider, WebLogic JNDI is supported by the underlying WebLogic framework for all its communications. There is a single connection from the client application to the WebLogic Server, and there is a single connection from the WebLogic Server to the server or backend process on which the delegate service provider depends for its objects.

If you are accessing a JNDI/LDAP object through another service, however -- perhaps the object is being called as an Event action -- it will not lead to a performance/resource penalty for connection-related resources. WebLogic multiplexes all connections between a client and a WebLogic Server on a single socket, so you may have various types of traffic -- including JDNI objects, WebLogic Events, and JDBC -- all using the same connection. Consequently, the overhead for your client application's connections is always the same, no matter which or how many of the enterprise APIs your client program uses.

WebLogic creates the delegated context on the WebLogic Server and wraps it in a remote object that implements the same interface, which then delegates its calls to the original context. The remote wrapper is exported to the client. When the client invokes a method on the remote wrapper, the call to the context blocks and the method calls is propagated to the server, where the original delegated context method call is invoked; that is, the only the client thread blocks. After the result is returned to the client, the client thread is unblocked and can continue processing with the result. Note that calls to list() and listBindings() do not require that all bindings be collected before returning; in this case, the remote context returns a special NamingEnumeration that pulls over a subset of the bindings with each call to next().

Looking up an object

Once you have obtained a Context, you can use it to look up and retrieve named objects. You look up an object by the name under which it was bound when it was first placed in the name system.

The following code retrieves an Enterprise Java Bean named "SeviceBean":

  try { 
    ServiceBean bean = (ServiceBean)ctx.lookup("ejb.serviceBean");
  }
  catch (NameNotFoundException e) {
    // binding does not exist
  }
  catch (NamingException e) {
    // a failure occurred
  }

Top

Using JNDI in a distributed application environment

For an object to be useable in a distributed environment, it must be bound to a name in the name system so that clients of the name system have an unambiguous way to ask for a reference to the object. Then a client calls the Context.lookup() method with the name as an argument, and is returned an object.

JNDI provides several ways to hook into the object retrieval machinery so that the implementor of a naming service can control what object is ultimately returned to the client performing a lookup. Objects can be stored as references (which encapsulate a factory for reconstructing the object on retrieval). It is also possible to specify an object factory that will be given the opportunity to transform objects retrieved from a naming service.

When a client retrieves an object from the naming service, the object should be useable in a meaningful way. If the client retrieves a Printer object, for example, the client should be able to use this object to print.

In a distributed environment, this requires that objects returned by lookup can be transported from the server to the client in a form that preserves their functionality. For simple objects that have no state, this can be achieved by returning an object that is serializable (that is, that implements java.io.Serializable). Whenever the lookup() method returns a serializable object to a client, the client actually receives a copy of the original object.

Practically, when binding from the client, only Remote objects or simple serializable Objects that represent values can be bound to a name (in effect, a replacement for calls to RMI's Naming.bind()).

Making an object available by binding it to a name

After an object is bound to a name in a name system, any client that has access to that name system can retrieve it. This implies that all objects bound in the name system should be useable in a distributed environment; that is, the object that one client "binds" into the naming tree must be useable by any clients that can look it up.

At the least, such a concept of usability requires that the bound object be serializable. (In some cases, the object must also have a remote component, which we cover in the next section).

Here we illustrate the simplest case of making an object available to clients of a name system in a distributed environment, by demonstrating how to bind a string in the WebLogic name space. Because String implements java.io.Serializable, any client that looks up the object will get a copy of the string.

  try {
    ctx.bind("testMessage", "this is a test");
  }
  catch (NamingException e) {
    // a failure occurred
  }

Making an object transportable

For objects that have state or refer to a shared resource, a remote object that is transportable should be returned -- that is, an object that implements java.rmi.Remote, weblogic.rmi.Remote, or in some other way provides access to an object that resides on a remote VM.

A Printer is an example of an object for which a remote implementation is natural. If the printer object bound in the namespace implements Remote, a lookup will cause a remote stub to be returned to the client. This stub will delegate to the actual implementation, which resides in the VM in which the actual object was created. Here, we refer to objects that can be passed to and effectively used in the client VM as transportable objects.

There are two ways to ensure that an object returned from a lookup (or search) is transportable. The first is to bind only transportable objects in the namespace. We recommend this approach whenever possible; it is simple and direct. Since every object bound in the namespace is transportable, any object can be passed freely between VMs without exception.

The second way to ensure that an object returned by a call to Context.lookup() is transportable is to use object factories to transform non-transportable objects bound in the namespace into transportable objects that can be passed on to the client. This approach may be required in cases where it is not possible to ensure that objects bound in the namespace are transportable.

A TransportableObjectFactory provides one method that takes a non-transportable object and returns a transportable representative of that object. It must implement the following interface:

interface TransportableObjectFactory { 
  Object getTransportableInstance(Object boundObject, Properties props)
        throws Exception; 
  }

The getTransportableInstance() method is called with an object being retrieved from the namespace as its argument. It can either return null, which signals that it doesn't handle objects of the given type, or a new object that will act as a transportable representative of the bound Object. The new object must implement java.io.Serializable so that the object can be successfully returned to the client.

Transportable factories are registered with the WebLogic Server by setting the weblogic.jndi.transportableObjectFactories server property in the weblogic.properties file. (For more information on the properties file, read the WebLogic Administrators Guide document, Setting WebLogic properties.) This property should contain a comma-separated (,) list of classes that implement the TransportableObjectFactory interface. Whenever WebLogic JNDI retrieves an object from a namespace, it will call each factory in the list in succession until one of the factories creates a new object. If all of the factories return null for the bound object, the bound object is passed to the client in whatever state it exists.

Top

Setting up ACLs for JNDI in the WebLogic Realm

ACL: weblogic.jndi.service

WebLogic controls access to internal resources like JNDI through ACLs set up in the WebLogic Realm. Entries for ACLs in the WebLogic Realm are listed as properties in the weblogic.properties file. The access control list name for JNDI is weblogic.jndi.service, where service is the name of an object or service.

You can set the Permissions "lookup", "modify", and "list" for JNDI by entering a property in the properties file. If you do not set an ACL for JNDI, all permissions are by default granted to everyone.

Here is a breakdown of how these permissions map to actual JNDI methods:

  • lookup controls calls to lookup() and lookupLink()

  • list controls calls to list() and listBindings()

  • modify controls calls to bind(), rebind(), rename(), createSubcontext(), destroySubcontext()

In the first two examples, we illustrate how you might set ACLs for looking up or modifying RMI objects. Peter, Brown, and Eric can look up and use RMI objects, but only the system user can change RMI objects.

The third example shows how you might set an ACL for listing bound objects in the "myapps" context. Only Peter, Brown, and Eric can obtain a list of objects bound to the "myapps" context.

Example:
weblogic.allow.lookup.weblogic.jndi.weblogic.rmi=peter,brown,eric weblogic.allow.modify.weblogic.jndi.weblogic.rmi=system weblogic.allow.list.weblogic.jndi.myapps=peter,brown,eric

 

Copyright © 2000 BEA Systems, Inc. All rights reserved.
Required browser: Netscape 4.0 or higher, or Microsoft Internet Explorer 4.0 or higher.
Last updated 03/03/2000