9. Design Choices

9.1 Separation of Interfaces into Context and DirContext

There are two core interfaces in JNDI: Context , and DirContext , with DirContext extending the base naming operations in Context with directory service operations. They have been separated into separate interfaces both for modularity and also in keeping with the "pay for what you use" goal of JNDI.

Naming is a basic component found in many computing services such as file systems, spreadsheets, calendar services, and directory services. By having a base Context interface for the naming operations, we enable its use by all these other services, not just for directory services.

DirContext extends Context to provide basic directory service operations, which include manipulation of attributes associated with named objects, attribute-based searches, and schema-related operations of those attributes and named objects.

9.2 Separation of JNDI into Different Functional Packages

JNDI is separated into four client packages ( javax.naming , , javax.naming.event , javax.naming.ldap ) and a service provider package ( javax.naming.spi ). The idea is that each package contains the interfaces and classes required for a particular category of applications, again in keeping with the "pay for what you use" goal. For example, an application that just wants to perform name-lookups only needs to use the javax.naming package. An application that wants to examine/modify attributes associated with an object uses the javax.naming and packages. An application that needs to use LDAP-specific controls or extended operations uses the javax.naming.ldap package. There is a step-by-step progression of what classes and interfaces each category of application writer needs to learn and use.

9.3 Separation of Client APIs and Service Provider Interfaces

JNDI separates interfaces and classes that a client application needs to use from those that are only of interest to service providers into different packages. For example, a client would use interfaces and classes from javax.naming , while a service provider that is hooking up a naming service would use both javax.naming and javax.naming.spi . The package delineation minimizes confusion for the application developer and makes clear which packages he needs to examine when writing his program.

9.4 Multiple methods for listing Context

There are two common types of applications that list contexts: browser-style applications, and applications that need to perform operations on the objects in a context en-masse. Browser-style applications typically want to display the names of the contents of a context. In addition to the names, many browsers often require type information of the objects bound to the names, so that it can display appropriate pictorial representations of the objects. The browser is usually interactive. Once a user has used a browser to display the contents of a context, he would then select one or a few of the entries displayed and request more information on it.

Some applications need to perform operations on objects within a context en-masse. For example, a backup program might want to perform "file stats" operations on all the objects in a file directory. A printer administration program might want to restart all the printers in a building. To perform such operations, these programs need to obtain all the objects bound in a context.

With these two common styles of usage in mind, the Context interface has two types of list methods: list() and listBindings() . list() returns a list of name/class-name pairs while listBindings() returns a list of name/class-name/object tuples. list() is designed for browser-style applications that want mostly just the names and types of objects bound in a context. listBindings() is for applications that want to potentially get all the objects in the context, as well as their names and types. listBindings() returns an enumeration of Binding . Both the listBindings() operation itself and invocation of methods in the Binding class (e.g. getObject() ) could be implemented lazily or eagerly. Using listBindings() simply indicates the potential that the caller might want all or many of the objects in the context so that implementations that are able can optimize for it. Using list() indicates that the caller is unlikely to want all, if any, objects in the context so implementations can optimize for that if possible.

An alternative is to have a single list operation and have the lazy or eager behavior as part of the implementation of Binding . The advantage of this is that there is a single list operation to learn. The disadvantage is that the caller has no way of indicating which piece of information he wants back from list, and subsequently, implementations cannot optimize for the eventual behavior of the program.

9.5 Support for Federation

Federation is a first-class concept in JNDI. In the client interfaces, it is supported by the use of the Name interface for specifying names that can span one or more namespaces. The caller of the methods in the client interface need not know anything else regarding federation. Resolution of names across multiple systems is handled by the SPI and does not involve any intervention on the part of the caller.

Although federation is a first-class concept, that does not mean that all callers and service providers must make use of it. If an application or service does not want to take advantage of federation, there is no requirement that Name always span multiple namespaces. Name can just name objects within a single namespace, and the SPI can handle name resolution within a single namespace as well (as a degenerate case of multiple namespace support).

9.6 DirContext versus DirObject

Instead of having DirContext extend Context , an alternative would be to not extend Context at all but to have a separate interface called DirObject that encapsulates all the directory-related methods. In that case, an object can implement both Context and DirObject if it supports both the naming and directory operations; another object might implement just DirObject .

The problem with eliminating DirContext is that DirContext contains some hybrid operations that involve both naming and directories ( bind() , createSubcontext() methods that accept attributes as arguments). To keep these operations and have DirObject at the same time would produce the need for a third interface (perhaps called DirContext ) to contain just these hybrids.

Furthermore, having DirContext instead of DirObject is somewhat more convenient in that you can perform some operations in one step instead of two. For example DirContext.getAttributes() could be used to get the attributes associated with a named object, whereas with DirObject , you would need first to resolve to the object ( Context.lookup() ) and then use DirObject.getAttributes() to get the attributes from it.

9.7 Support for Schemas

The DirContext interface contains support for schemas. For example, from a DirContext object you can obtain its schema object, which points to the directory space where the schema for this particular DirContext instance is defined. From a DirContext object, you can also obtain its schema class definition (i.e. information about what type of object this represents in the directory). There is further support for schemas in the Attribute class, which contains methods for obtaining an attribute's syntax information (i.e. what is the type of the attribute's value) and the attribute's definition (e.g. is it multivalued, syntax, constraints on its syntax). There is no requirement that any of this schema information be dynamically accessible (i.e. points to live directory spaces). Support for such schema information could be generated statically by the service provider. For example, a particular directory service might only support string attribute values, so it can hard-wire the syntax of the attributes that it returns. Another directory might support only static schemas (where information in the schema are not modifiable). Yet another directory might support fully dynamic schemas. The interfaces and classes in DirContext are flexible enough that these different levels of support for schemas can be accommodated.

9.8 Overloaded Methods in Context and DirContext

For each method in the Context and DirContext interfaces that accepts a Name argument, there is a corresponding overloaded form that accepts a String argument for specifying a name.

The motivation for having the String -based methods is that there are many applications that simply accept a string name from the end-user and perform context methods on the object named by that string name. For those applications, it is useful to have the context methods accept a string for the name directly, instead of requiring the applications to first construct a Name object using the string name.

The motivation for having the Name -based methods is that there are also many applications that manipulate names and do not want to worry about syntactic details of the names' string forms when composing and modifying names. These applications deal with the parsed form of names and hence would prefer to deal with Name objects rather than string names. For these applications, we provide the Name -based methods in the context interfaces. Not providing these methods would probably cause proliferation of Name -like interfaces/classes to support manipulation of names in their structural form in applications developed on top of JNDI.

9.9 Reference and Referenceable

There are different ways in which applications and services can use the directory to locate objects. JNDI is general enough that it accommodates several different models. For some applications, the object bound in the directory is the object itself. An application may build up a dynamic directory while the application is active, and delete the directory when the application exits. Another application might store URLs as attributes for locating objects in its namespace. Other systems might bind some reference information in the directory, which can subsequently be used to locate or access the actual object. This last case is quite common, especially for making Java applications take advantage of services in the installed base. The reference in the directory acts as a "pointer" to the real object.

JNDI defines a Reference class to provide a uniform way of representing reference information. A Reference contains information on how to access an object. It consists of a list of addresses and class information about the object to which this reference refers. When binding a name to an object that is to be represented in the directory as a reference, the desired effect is that the object's reference be extracted and bound. To allow for this behavior, the object's class must implement the Referenceable interface, which contains the method getReference() .

There is some similarity between the interfaces Serializable and Referenceable and a natural question is "why not just use Serializable instead?" The answer is that a serialized object is really a frozen version of the object, whereas the reference contains just the information needed to construct it. The serialized version may have a lot more state which may not be appropriate for storage in the directory.

9.10 Automatically Turning References into Objects

For an object that is bound as a Reference in the directory, JNDI SPI framework automatically creates and instantiates the object identified by the reference. In this way, the program can simply narrow the result of lookup() to the expected class, instead of calling a separate operation to transform the result of lookup() into an object of the expected class.

For example, if you are looking up a printer object, a successful lookup would return to you a printer object that you can directly use.

Printer prt = (Printer) ctx.lookup(somePrinterName);

JNDI does this automatically, instead of requiring an explicit conversion step, because this is expected to be the common usage pattern. By having the Reference class, and a common mechanism for converting a Reference into the object identified by the Reference , JNDI encourages different applications and system providers to utilize this mechanism, rather than inventing separate mechanisms on their own.



Copyright © 1993, 2018, Oracle and/or its affiliates. All rights reserved.