Whole document tree 1 IntroductionThe JNDI SPI provides the means by which developers can write different naming and directory service providers and make them available so that the corresponding services are accessible from applications that use the JNDI API. A service provider is a set of modules that together satisfy JNDI API requests. In addition, because JNDI allows the use of names that span multiple namespaces, one service provider implementation may need to interact with another in order to complete an operation. The SPI provides methods that allow different provider implementations to cooperate to complete client JNDI operations. This document describes the components of the SPI and explains how developers can build service providers for JNDI. It is assumed that the reader is familiar with the contents of the JNDI API document. All service provider developers should read the "Security Considerations" section of the JNDI API document. It contains important issues that all developers using JNDI, especially those writing service providers, should consider. 1.1 Document Overview
There are several types of implementations that sit beneath the JNDI API. A service provider contains at a minimum a context implementation. A context implementation implements the A context implementation can be accessed in different ways. The most common way is to access it from the initial context. Chapter 3 describes two ways that a context implementation can be accessed from the initial context: via an initial context factory and a URL context factory. The JNDI architecture defines components/implementations that can be used to augment the behavior of context implementations. This allows users and applications to customize the implementation. These components are supported through factories. JNDI defines three types of factories and provides SPI methods that make use of them. These factories are described in Chapter 4.
1.2 Interface1 Overview
The JNDI SPI is contained in the package 1.2.1 NamingManager and DirectoryManager
The 1.2.2 Initial Contexts
1.2.3 Object Factories
1.2.4 State Factories
1.2.5 Federation Support
The
2 Building a Context Implementation
One of the basic tasks in building a service provider is to define a class that implements the 2.1 Ownership of Parameters
In general, any object passed as a parameter to methods in the
For purposes of parameter ownership, an operation on a context instance is not considered to have completed while any referrals generated by that operation are still being followed, or if the operation returns a 2.2 ReentrancyA context instance need not be reentrant. Two threads that need to access the same context instance concurrently should synchronize amongst themselves and provide the necessary locking. However, different context instances must be safe for concurrent multithreaded access. That is, two threads each operating concurrently on their respective context instance should not need to synchronize their access. For example, even though two contexts might share the same resources (such as the same connection), it must be possible (and safe) for two separate threads to operate on each of those contexts without the threads having to do any explicit synchronization.
For purposes of concurrency control, an operation on a context instance is not considered to have completed while any referrals generated by that operation are still being followed, or if the operation returns a 2.3 Basic Support-Implementing the Context Interface(s)
The context implementation defines implementations for each of the methods in the
If a method is not supported, it should throw
For methods in the Appendix A contains an example context implementation that implements a flat, in-memory namespace. 2.4 Object Support
JNDI encourages providers to supply implementations of the Context ctx = new InitialContext(); Printer prt = (Printer)ctx.lookup(somePrinterName); prt.print(someStreamOfData); Similarly, when storing an application's object into the underlying service, it is most portable and convenient if the application does not have to know about the underlying data representation. However, what is bound in the underlying directory or naming services typically are not objects in the Java programming language but merely reference information which can be used to locate or access the actual object. This case is quite common, especially for Java applications accessing and sharing services in an existing installed base. The reference in effect acts as a "pointer" to the real object. In the printer example, what is actually bound might be information on how to access the printer (e.g., its protocol type, its server address). To enable this easy-to-use model for the application developer, the context implementation must do the transformation of the data to/from the underlying service into the appropriate objects in the Java programming language.
There are different ways to achieve this goal. One context implementation might have access to all the implementation classes of objects that a directory can return; another context implementation might have a special class loader for locating implementation classes for its objects. JNDI provides the JNDI provides utilities for context implementations to use when reading/storing objects in the Java programming language in a format-independent way to the underlying service. This section describes these utilities. These utilities interact with components called object and state factories that do the actual transformations. These factories are described in Chapter 4. 2.4.1 Reading an ObjectJNDI provides the following methods that context implementations should use to transform data read from the underlying service into objects in the Java programming language: Object NamingManager.getObjectInstance(Object refInfo, Name name, Context nameCtx, Hashtable env) throws Exception; Object DirectoryManager.getObjectInstance(Object refInfo, Name name, Context nameCtx, Hashtable env, Attributes attrs) throws Exception; refInfo is the data (representing the object) read from the underlying service. name is the name of the object while nameCtx is the context in which to resolve name . The
name /nameCtx pair can be used to obtain more information about the object than is available from refInfo . env is the environment of the context from which getObjectInstance() is being invoked. attrs is the collection of attributes read from the directory about the object, usually in the same request that was used to get refInfo . It might not be the complete collection of attributes if such was not requested.
The method in the
When constructing objects to be returned for the following methods, the context implementation should call javax.naming.Context.lookup(Name name) javax.naming.Context.lookupLink(Name name) javax.naming.Binding.getObject() javax.naming.directory.SearchResult.getObject()
For
Here is an example. Suppose printers are represented in the namespace using Object lookup(Name name) { ... Reference ref = <some printer reference looked up from naming service>; return NamingManager.getObjectInstance(ref, name, this, env); }
In another example, suppose printers are represented in the directory as a collection of attributes. To turn a printer's directory entry into a live Object lookup(Name name) { ... Attributes attrs = <read attributes from directory>; Reference ref = <construct reference from attributes>; return DirectoryManager.getObjectInstance(ref, name, this, env, attrs); } 2.4.2 Storing an ObjectJNDI provides the following methods that context implementations should use to transform an object before storing it in the underlying service: Object NamingManager.getStateToBind( Object obj, Name name, Context nameCtx, Hashtable env) throws NamingException; DirStateFactory.Result DirectoryManager.getStateToBind( Object obj, Name name, Context nameCtx, Hashtable env, Attributes attrs) throws NamingException;
The method in the
Before storing an object supplied by the application, the context implementation should call javax.naming.Context.bind(Name name, Object o) javax.naming.Context.rebind(Name name, Object o) javax.naming.DirContext.bind(Name name, Object o, Attributes attrs) javax.naming.DirContext.rebind(Name name, Object o, Attributes attrs)
Here's an example of how a // First do transformation obj = NamingManager.getStateToBind(obj, name, ctx, env); // Check for Referenceable if (obj instanceof Referenceable) { obj = ((Referenceable)obj).getReference(); } if (obj instanceof Reference) { // store as ref } else if (obj instanceof Serializable) { // serialize } else { ... }
Here's an example of how a // First do transformation DirStateFactory.Result res = DirectoryManager.getStateToBind( obj, name, ctx, env, inAttrs); obj = res.getObject(); Attributes outAttrs = res.getAttributes(); // Check for Referenceable if (obj instanceof Referenceable) { obj = ((Referenceable)obj).getReference(); } if (obj instanceof Reference) { // store as ref and add outAttrs } else if (obj instanceof Serializable) { // serialize and add outAttrs } else if (obj instanceof DirContext) { // grab attributes and merge with outAttrs } else { ... }
As shown in these examples, a context implementation might be able to store different types of objects ( If a context implementation can store different types of objects, it should follow this order for the following common types: This order is recommended because it is most likely to capture the intent of the caller of thebind() /rebind() method. For example, a Reference is Serializable , so if you performed the Serializable check first, no Reference objects would ever be stored in the reference format (that is, they would all be serialized).
2.5 Federation Support2.5.1 NamesWhen a context is given a string name argument, the name represents a composite name that may span multiple namespaces, or it may have only a single compound name component (which in turn may be made up of one or several atomic names) that belongs to a single namespace. The context implementation must determine which part of the name is to be resolved/processed in its context and pass the rest onto the next context. This may be done syntactically by examining the name, or dynamically by resolving the name.
When a context is given a 2.5.2 Resolving Through a Context
A context participates in a federation by performing the resolution phase of all of the context operations. The Figure 1: Example of Resolving through Intermediate Contexts to Perform a bind(). ![]()
For example, suppose a context does not support the 2.5.3 Resolving Through to Subinterfaces of Context
To invoke a From the context implementation's perspective, in order to retrieve the attributes,DirContext ctx = new InitialDirContext(); Attributes attrs = ctx.getAttributes(someName); getAttributes() might need to traverse multiple naming systems. Some of these naming systems only support the Context interface, not the DirContext interface. These naming systems are being used as
intermediaries for resolving towards the target context. The target
context must support the DirContext interface. Figure 2 shows an example of this.
Figure 2: Example of Resolving Through Intermediate non-DirContexts ![]()
In order for intermediate naming systems to participate in the federation for extensions of public interface Resolver { public ResolveResult resolveToClass(Name name, Class contextType) 2.5.4 Naming System BoundariesThe resolution of a (multicomponent) composite name proceeds from one naming system to the next, with the resolution of the components that span each naming system typically handled by a corresponding context implementation. From a context implementation's point of view, it passes the components for which it is not responsible to the (context implementation of the) next naming system.
There are several ways in which the context implementation for the next naming system may be located. It may be done explicitly through the use of a junction, where a name in one naming system is bound to a context (or a
Alternately, the next naming system may be located implicitly. For example, a context implementation may choose the next naming system based upon service-specific knowledge of the object that it has resolved. For example, with the composite name "ldap.wiz.com/cn=fs,ou=eng", the DNS name However the next naming system is located, the context implementation must hand the next naming system the remaining portion of the composite name to resolve. 2.5.5 Continuing an Operation in a Federation
In performing an operation on a name that spans multiple namespaces, a context in an intermediate naming system needs to pass the operation onto the next naming system. The context does this by first constructing a
It then obtains a continuation context from JNDI by passing the public class NamingManager { public static Context getContinuationContext( CannotProceedException e) throws NamingException; ... }
The information in the exception is used by
To obtain a continuation context for the public class DirectoryManager { public static getContinuationDirContext( CannotProceedException e) throws NamingException; ... } Upon receiving the continuation context, the operation should be continued using the remainder of the name that has not been resolved.
For example, when attempting to continue a public void bind(Name name, Object obj) throws NamingException { ... try { internal_bind(name, obj); ... } catch (CannotProceedException e) { Context cctx = NamingManager.getContinuationContext(e); cctx.bind(e.getRemainingName(), obj); } }
In this example, 2.5.6 "Dynamic" Location of Next Naming SystemIn some federation configurations, the result of resolution in one naming system does not indicate which is the next naming system. The only conclusion that the context implementation can draw is that resolution has terminated in the current naming system and should proceed to the next naming system. For example, suppose the composite name "lib/xyz.zip/part1/abc" consists of two parts: "lib/xyz.zip", which names a file in ZIP format, and "part1/abc", which names an entry within the ZIP file. Although the resolution of "lib/xyz.zip" results in a file object, the desired result is a context in which to resolve names of ZIP entries. Similarly, another composite name could name an entry within a file in "tar" format, and the desired result of the resolution of the file component of the composite name would be a context in which to resolve tar entries. In effect, any type of context might be federated beneath the file system namespace depending on the format of the files. Such relationships should be symmetric: it should be possible for the ZIP file context and other similar contexts to federate beneath other, non-file system namespaces. Furthermore, developers writing the file system context implementation and those writing the context implementations for the ZIP file context, the tar file context, or a context for some yet-to-be defined format, should be able to work independently.
To support this type of federation, JNDI defines a special form of RefAddr addr = new RefAddr("nns") { public Object getContent() { return theFile; } }; Reference ref = new Reference("java.io.File", addr);
Next, the context implementation constructs a
As with any resolved object in a 2.5.7 More about CannotProceedException
Central to the JNDI SPI's framework for federation is the 2.5.8 Contextual InformationWhile the emphasis of the JNDI SPI framework is on "looking forward" and trying to find the next naming system, some context implementations, once located, need to "look back" the resolution chain to obtain contextual information. For example, a particular context implementation that is federated off of a host naming system might be designed such that the only means by which it can find out host information is to ask its (possibly not immediate) superior naming system. To do that, it needs contextual information-information about how the resolution proceeded to its current point.
Summarizing earlier discussions on federation, when performing an operation on a name that spans multiple namespaces, the context implementation first constructs a 2.6 Referral Support
LDAP-style directory services support the notion of referrals for redirecting a client's request to another server. A referral differs from the federation continuation mechanism described earlier in that a referral may be presented to the JNDI client, who then decides whether to follow it, whereas a
A context implementation that supports referrals defines a subclass of
The environment property while (true) { try { bindings = ctx.listBindings(name); while (bindings.hasMore()) { b = (Binding) bindings.next(); ... } break; } catch (ReferralException e) { ctx = e.getReferralContext(); } } This convention of re-invoking the method using the original arguments is a simple one for applications to follow. This places the burden on the implementation of the ReferralException to supply enough information to the implementation of the referral context for the operation to be continued. Note that this will likely render some of the arguments passed to the re-invoked operation superfluous. The referral context implementation is free to ignore any redundant or unneeded information. It is possible for an operation to return results in addition to a referral. For example, when searching a context, the server might return several results in addition to a few referrals as to where to obtain further results. These results and referrals might be interleaved at the protocol level. If referrals require user interaction (i.e., not followed automatically), the context implementation should return the results through the search enumeration first. When the results have been returned, the referral exception can then be thrown. This allows a simple programming model to be used when presenting the user with a clear relationship between a referral and its set of results. 2.7 Schema Support
JNDI defines the public class Attribute { public DirContext getAttributeDefinition() throws NamingException; public DirContext getAttributeSyntaxDefinition()
The utility class,
The public class DirContext { ... public DirContext getSchema(Name name) throws NamingException; public DirContext getSchema(String name) throws NamingException; public DirContext getSchemaClassDefinition(Name name) throws NamingException; public DirContext getSchemaClassDefinition(String name) throws NamingException; }
2.8 Event Support
A context implementation supports event notification by providing implementation for the methods in the
The
Where possible, the context implementation should fire a 2.9 Context Environment Support
Each instance of Environment properties are defined generically in order to ensure maximum portability. Individual service providers should map these generic properties to characteristics appropriate for their service. Properties that are not relevant to a provider should be recorded and silently ignored. The environment may also be used for storing service provider-specific properties or preferences, in which case their applicability across different providers is limited. 2.9.1 Property Naming Convention
See Section 6.1 in the JNDI API document for a description of how environment properties are named. Service provider-specific properties should have a prefix that reflects their uniqueness to the provider. A common practice is to use the
package name of the service provider as the prefix. For example, since Sun's LDAP provider is primarily contained in the package 2.9.2 Initializing a Context's Environment
When creating an initial context (either using the constructors from
Like all other parameters, the environment parameter received by a context implementation is owned by the caller. The context implementation should make a copy of the environment parameter it gets or otherwise take steps to ensure that changes by the caller to the parameter would not affect what the context implementation sees and vice versa. Note also that if the environment parameter is a The JNDI library is responsible for merging properties from different sources, such as the environment parameter to the initial context, resource files, and, where appropriate, system properties and applet parameters (see the JNDI API document, Chapter 6). The context implementation typically just reads the property it needs from the environment which it was supplied. There is seldom a need for a context implementation to consult other sources. 2.9.3 InheritanceThe environment is inherited from parent to child as the context methods proceed from one context to the next. The entire environment of a context instance is inherited by the child context instances, regardless of whether certain properties within the environment are ignored by a particular context.
A context implementation must pass on the environment from one context instance to the next in order to implement this "inheritance" trait of environments. Within one context implementation it can do so by passing the environment as an argument to the
Across context implementations in a federation, this is supported by passing the environment as part of the Inheritance can be implemented in any way as long as it preserves the semantics that each context has its own view of its environment. For example, a copy-on-write implementation could be used to defer copying of the environment until it is absolutely necessary. 2.9.4 Updates to the Environment
The environment of a context can be updated via the use of the public interface Context { ... public Object addToEnvironment(String propName, Object propVal) throws NamingException; public Object removeFromEnvironment(String propName) throws NamingException; }
These methods update the environment of this instance of See Section 6.6 in the JNDI API document for details. 2.9.5 Provider Resource FilesEach service provider has an optional resource file that contains properties specific to that provider. The name of this resource is: where prefix is the package name of the provider's context implementation(s), with each period (".") converted to a slash ("/"). For example, suppose a service provider defines a context implementation with class name[prefix/]jndiprovider.properties com.sun.jndi.ldap.LdapCtx . The provider resource for this provider is named com/sun/jndi/ldap/jndiprovider.properties .
The JNDI class library will consult this file when it needs to determine the value of a property, as described in Section 6.5.2 in the JNDI API document. When the service provider needs to determine the value of a property, it will generally take that value directly from the environment. The service provider may define provider-specific properties to be placed in its own provider resource file. In that case it needs to read them from its property resource file and merge them in a way consistent with the algorithm described in Section 6.5.2 in the JNDI API document. 2.10 Connection ManagementFor a context implementation that uses a client/server protocol, there is not necessarily a one-to-one mapping between a context and a connection between the client and the server. JNDI is a high-level API that does not deal directly with connections. It is the job of the context implementation to do any necessary connection management. Hence, a single connection may be shared by multiple context instances, and a context implementation is free to use its own algorithms to conserve connection and network usage. Thus, when a method is invoked on the context instance, the context implementation might need to do some connection management in addition to performing the requested operation.
The Some environment properties affect a context's connection. For example, if the application changes the security-related properties, the context implementation might need to modify or create a new connection using those updated properties. If the connection was being shared by other contexts prior to the change, the connection change should not affect contexts whose properties have not been updated. 3 The Initial ContextSince all naming methods are performed relative to a context, an application needs a starting context in order to invoke them. This starting context is referred to as the initial context. The bindings in the initial context are determined by policies set forth by the initial context implementation, perhaps using standard policies for naming global and enterprise-wide namespaces. For example, the initial context might contain a binding to the Internet DNS namespace, a binding to the enterprise-wide namespace, and a binding to a personal directory belonging to the user who is running the application. An application obtains an initial context by making the following call: An alternate constructor allows an environment to be passed as an argument. This allows the application to pass in preferences or security information to be used in the construction of the initial context.Context ctx = new InitialContext(); Hashtable env = new Hashtable();4 env.put(Context.SECURITY_PRINCIPAL, "jsmith"); env.put(Context.SECURITY_CREDENTIALS, "xxxxxxx"); Context ctx = new InitialContext(env);
Subsequent to getting an initial context, the application can invoke Object obj = ctx.lookup("this/is/a/test");
The
The 3.1 The Initial Context Factory
An initial context factory is a class that creates an instance of a context that has been implemented following the guidelines outlined in Chapter 2. The factory is used by the
Given an environment, the factory returns an instance of public interface InitialContextFactory { public Context getInitialContext(Hashtable env)
Appendix A contains an example of an
Once the context instance has been created, when a method is invoked on
JNDI selects the initial context implementation to use by using the property
An application that wants to use a particular initial context must supply the 3.1.1 Exceptions
When the property
If the property 3.2 URL Support
If a URL5 string is passed to the initial context, it will be resolved using the corresponding URL context implementation. This feature is supported by the This feature allows applications to use the initial context to reach any namespace for which a URL context implementation has been made available. For example, the following code lists an LDAP namespace from the initial context:
3.2.1 URL ContextA URL string has the following format: For example, an LDAP URL string has the scheme id "ldap"; a file URL has the scheme id "file".
A URL context implementation is a class that implements the
When a URL string name is passed to a URL context, the context methods that accept
Name arguments that are not URL strings, and URL strings with an inappropriate scheme id should be rejected with an 3.2.2 URL Context FactoryA URL context factory is a class (actually a special type object factory (see Section 4.1)) that creates an instance of a URL context for URLs of one or more schemes.
When the
package_prefix + "." + scheme_id + "." + scheme_id
for each package prefix listed in the property. The default package prefix
For example, if the URL is " The factory class implements thecom.widget.ldap.ldapURLContextFactory com.wiz.jndi.ldap.ldapURLContextFactory com.sun.jndi.url.ldap.ldapURLContextFactory ObjectFactory interface (see "URL Context Factory" on page 31) and has a public constructor that takes no arguments. The InitialContext class passes the scheme id as the resolved object to the factory's getObjectInstance() method, which in turn creates a URL context for the URL scheme. The URL context will then be used to carry out the originally intended Context or DirContext operation on the URL supplied to InitialContext .
3.2.3 Service Provider's Responsibility
There is no requirement that a service provider supply a URL context factory and URL context implementation. It only does so if it wants to allow URL string names with its URL scheme to be accepted by the 3.3 Overriding the Default Behavior
The policy of creating an initial context factory using the 3.3.1 Removing URL Support
If an application does not want URL strings to be treated specially, it can use the method
This method is also useful if the application needs to access interfaces implemented by the context created by the initial context factory, but which are not one of Note that installing an initial context factory builder (discussed next) affects the result ofFooContext ctx = (FooContext) NamingManager.getInitialContext(env); ... Object obj = ctx.lookup(name); ctx.fooMethod1(...); NamingManager.getInitialContext() .
3.3.2 Removing All PolicyAn initial context factory builder is a class that creates instances of initial context factories.
An application can install an initial context factory builder to define its own policy of how to locate and construct initial context implementations. When a builder has been installed, it is solely responsible for creating the initial context factories. None of the default policies (
An implementation of an initial context factory builder must implement the
After a builder has been installed. the application can get the initial context by either using the 3.4 Implementing a Subclass of InitialContext
When there is a need to provide an initial context that supports an interface that extends from 3.4.1 URL Support
To add support for URLs in the same way
For example, suppose When providing implementations for the new methods in thepublic class InitialFooContext extends InitialDirContext { ... protected FooContext getURLOrDefaultInitFooCtx(Name name) throws NamingException { Context answer = getURLOrDefaultInitCtx(name); if (!(answer instanceof FooContext)) { throw new NoInitialContextException("Not a FooContext"); } return (FooContext)answer; } // similar code for getURLOrDefaultInitFooCtx(String name) } FooContext interface that accept a name argument, getURLOrDefaultInitFooCtx() is used in the following way.
public Object FooMethod1(Name name, ...) throws NamingException { return getURLOrDefaultInitFooCtx(name).FooMethod1(name, ...); } 3.4.2 New Method Support
When providing implementations for the new methods in the protected FooContext getDefaultInitFooCtx() throws NamingException { Context answer = getDefaultInitCtx(); if (!(answer instanceof FooContext)) { throw new NoInitialContextException("Not an FooContext"); } return (FooContext)answer; } public Object FooMethod2(Args args) throws NamingException { return getDefaultInitFooCtx().FooMethod2(args); } 3.4.3 Constructors
The implementation should provide appropriate constructors for the class. The constructor should call the appropriate constructor of the superclass. If the environment needs to be modified or examined prior to the superclass's constructor being called, it should use the protected constructor that accepts a boolean flag to control the initialization of the initial context, and then use the Client programs that use this new initial context would look as follows.public InitialFooContext(Hashtable environment, Object otherArg) throws NamingException { super(true); // don't initialize yet // Clone environment and adjust Hashtable env = (environment == null) ? new Hashtable(11) : (Hashtable)environment.clone(); ... init(env); } import com.widget.jndi.InitialFooContext; ... FooContext ctx = new InitialFooContext(env); Object obj = ctx.lookup(name); ctx.FooMethod1(name, ...); 4 Customizing A Context ImplementationJNDI allows a context implementation to be customized-by the application, the application's deployer or user, or the service provider-in how it reads and stores objects in the naming/directory service. A similar facility is also available for narrowing LDAP v3 control classes. You can think of these facilities as modules that plug into a context implementation. 4.1 Reading Objects: Object Factories
JNDI provides a generic way of creating objects (including instances of
Given some reference information (public interface ObjectFactory { public Object getObjectInstance(Object refObj, Name name, Context nameCtx, Hashtable env) throws Exception; } public interface DirObjectFactory extends ObjectFactory { public Object getObjectInstance(Object refObj, Name name, Context nameCtx, Hashtable env, Attributes attrs) throws Exception; } refObj ) about an object, optional information about the name of the object and where it is bound, and optionally some additional environment information (for example, some identity or authentication information about the user creating the object), the factory attempts to create an object represented by the reference information. For example, given reference information about a printer, a printer object factory might return an instance of Printer . In the case of an object factory that is to be used with a DirContext implementation, the factory is also given some attributes about the object. If the factory requires more attributes or information, it can obtain them directly from the naming/directory service by using the name /nameCtx arguments.
If the factory cannot created an object using the arguments supplied, it should return Object factories are used in several places in JNDI, basically to turn any reference information into an object. They are used in federation, URL processing in the initial context, and, as illustrated by the printer example, turning data into a form expected by the application. 4.1.1 Handling Structured References
A If the object read from the directory/naming service is an instance ofpublic class Reference { ... public String getClassName(); public String getFactoryClassName(); public String getFactoryClassLocation(); } Reference or Referenceable , its corresponding object factory can be located using information in Reference . The getFactoryClassName() method retrieves the name of the factory class that implements the ObjectFactory interface. This factory must implement the ObjectFactory interface and have a public constructor that takes no arguments. getFactoryClassLocation() retrieves the codebase of the class implementation for the factory, which is a list of space-separated URLs.
JNDI creates the object by invoking Note that all the classes necessary to instantiate the object returned to the application are made available using mechanisms provided by JNDI. The application doesn't have to install the classes locally. Figure 3: Example Using Reference to Get Back an Object From the Namespace ![]()
Returning to the printer example, suppose
From the context implementation's point of view, all of this is done automatically by its invocation of
When the application invokes A service provider for such an object must do the following:
4.1.2 Handling URL References
If a A service provider for such an object must do the following:
4.1.3 Handling Arbitrary References: The java.naming.factory.object Property
In addition to extracting factory information from Figure 4: Example using java.naming.factory.object to Get Back an Object from the Namespace ![]()
For the printer example, instead of using a A service provider for such an object must do the following:
The service provider should automatically convert between the actual object (e.g.,
An application that wants to use a particular factory for generating objects must include the factory's class name in its 4.1.4 Overriding the Default BehaviorAn object factory builder is a class that creates instances of object factories.
An application can install an object factory builder to defining its own policy of how to locate and construct object factory implementations. When a builder has been installed, it is solely responsible for creating the object factories. None of the default policies ( Figure 5: Example using an Object Factory Builder to Get Back an Object from the Namespece
![]() A service provider for an object factory builder must do the following:
An application that wants to use this factory builder must first install it. NamingManager.setObjectFactoryBuilder(builder); 4.1.5 Context Factory
A context factory is an object factory that creates instances of 4.1.6 URL Context Factory
A URL context factory is a special kind of context factory. It follows these rules when implementing
ldap://ldap.wiz.com/o=wiz,c=us " or "ldap://ldap.umich.edu/ ", ...).
getObjectInstance("ldap://ldap.wiz.com/o=wiz,c=us", null, null, env);
o=wiz,c=us " on the LDAP server ldap.wiz.com . If this happens to name a context, it can then be used for resolving (relative) LDAP names (e.g., "cn=Jane Smith ").
4.2 Storing Objects: State Factories
JNDI provides a mechanism to transform an object into a form storable by the underlying context implementation. That form may be any arbitrary type acceptable to the underlying context implementation. For example, it may be a Given an object (public interface StateFactory { public Object getStateToBind(Object obj, Name name, Context nameCtx, Hashtable env) throws NamingException; } public interface DirStateFactory { public DirStateFactory.Result getStateToBind(Object obj, Name name, Context nameCtx, Hashtable env, Attributes attrs) throws NamingException; } obj ), optional information about the name of the object and where it is bound, and optionally some additional environment information (for example, some identity or authentication information about the user accessing the namespace), the factory attempts to create an object suitable for binding. Typically, the state factory is knowledgeable about the target naming/directory service and/or context implementation, and knows which data formats are acceptable. In the case of a state factory that is to be used with a DirContext implementation, the factory is also given some attributes that are to be stored with the object. If the factory require more information about the object, it can obtain them directly from the naming/directory service by using the name /nameCtx arguments. For example, a printer state factory for an LDAP directory might return a set of attributes that represent the printer.
If the factory cannot return any data using the arguments supplied, it should return 4.2.1 Input/Output OptionsUltimately, a factory's output formats are determined by the underlying naming/directory service. A context implementation for the CORBA Object Services (COS) naming service, for example, can only store CORBA object references into the service; a context implementation for LDAP can only store attributes, although there is a lot of flexibility in how to encode information within those attributes. A service provider typically supplies a factory for each (common) type of input that it expects, and the application can augment that set with state factories of its own. For example, a service provider for COS naming might have a state factory for converting a Java Remote Method Invocation (RMI) object into a CORBA object reference. A user of that provider might add a state factory for converting a Microsoft COM object reference into a CORBA object reference. 4.2.2 Locating State Factories: The java.naming.factory.state Property
JNDI looks for state factories specified in the 4.3 Narrowing LDAP v3 Controls: Response Control Factories
The LDAP v3 protocol allows response controls to accompany any response sent by the server. The control consists of an OID string identifier and a sequence of ASN.1 BER encoded bytes. In the absence of any external information or assistance, the context implementation can only return a plain implementation of the JNDI provides the following abstract class for dealing with response controls: When a context implementation receives a response control, it invokes the staticpublic abstract javax.naming.ldap.ControlFactory { ... public static Control getControlInstance(Control ctl, Context ctx, Hashtable env) throws NamingException; public abstract Control getControlInstance(Control ctl) throws NamingException; } getControl-Instance() method to find a control factory that can narrow the control to one that has more user-friendly access methods. Such a control, for instance, can decode the ASN.1 BER bytes and provide access methods that return the information as Java types. If no such control factory can be found, the original response control is returned. Here is an example of a hypothetical Time-ResponseControl which decodes the time of day.
A control factory may be responsible for one or more controls. If the factory cannot return a control using the arguments supplied, it should returnpublic class TimeResponseControl implements Control { long time; // Constructor used by ControlFactory public TimeResponseControl(String OID, byte[] berVal) throws NamingException { // check validity of OID time = // extract time from berVal }; // Type-safe and User-friendly method public long getTime() { return time; } // Low-level methods public String getID() { return TIME_OID; } public byte[] getEncodedValue() { return // original berVal } ... } null . Typically, this involves just matching the control's OID against the list of OIDs supported by the factory. The factory should only thrown an exception if no other control factories should be tried. Therefore, the factory should be careful about exceptions that might be thrown from its implementation. For example, if a control factory is given a control with an OID that it supports, but the byte array has an encoding error, it should throw an exception.
Here is an example of a control factory: public class VendorXControlFactory extends ControlFactory { public VendorXControlFactory () { } public Control getControlInstance(Control orig) throws NamingException { if (isOneOfMyControls(orig.getID())) { ... // determine which of ours it is and call its constructor return new TimeResponseControl(orig.getID(), orig.getEncodedValue()); } return null; // not one of ours } } 4.3.1 Locating Response Control Factories: The java.naming.factory.control Property
JNDI looks for response control factories specified in the 4.4 Ownership of ParametersAny object passed as a parameter to a method in a factory is owned by the caller. Therefore, the factory is prohibited from maintaining a pointer to the object beyond the duration of the operation or modifying the object. If the factory needs to save the information contained in a parameter beyond the duration of the operation, it should maintain its own copy. 4.5 ReentrancyA factory instance should be reentrant. That is, it should be possible for multiple threads to invoke methods on a single instance of a factory concurrently. [Top] [Prev] [Next] [Bottom] 1 See Appendix B for legend of class diagram. 2 The CannotProceedException may well have been thrown by one of the context's internal methods when it discovered that the name being processed is beyond the scope of its naming system. The process by which the exception is produced is dependent on the implementation of the context.
3
Note that this is code in the application. In "Continuing an Operation in a Federation", the code sample presented is code in the context implementation.
4
You can also use a subclass of Hashtable (e.g. Properties) for this.
5
The mention of "URL" in this document refers to a URL string as defined by RFC 1738 and its related RFCs. It is any string that conforms to the syntax described therein, and may not always have corresponding support in the java.net.URL class or Web browsers. The URL string is either passed as the String name parameter, or as the first component of the Name parameter.
jndi@java.sun.com
Copyright © 1999, Sun Microsystems, Inc. All rights
reserved.
|