CONTENTS | PREV | NEXT | JNDI API |
There are two core interfaces in JNDI:
Context
, andDirContext
, withDirContext
extending the base naming operations inContext
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
extendsContext
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.
JNDI is separated into four client packages (
javax.naming
,javax.naming.directory
,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 thejavax.naming
package. An application that wants to examine/modify attributes associated with an object uses thejavax.naming
andjavax.naming.directory
packages. An application that needs to use LDAP-specific controls or extended operations uses thejavax.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.
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 bothjavax.naming
andjavax.naming.spi
. The package delineation minimizes confusion for the application developer and makes clear which packages he needs to examine when writing his program.
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()
andlistBindings()
.list()
returns a list of name/class-name pairs whilelistBindings()
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 ofBinding
. Both thelistBindings()
operation itself and invocation of methods in theBinding
class (e.g.getObject()
) could be implemented lazily or eagerly. UsinglistBindings()
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. Usinglist()
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.
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).
Instead of having
DirContext
extendContext
, an alternative would be to not extendContext
at all but to have a separate interface calledDirObject
that encapsulates all the directory-related methods. In that case, an object can implement bothContext
andDirObject
if it supports both the naming and directory operations; another object might implement justDirObject
.The problem with eliminating
DirContext
is thatDirContext
contains some hybrid operations that involve both naming and directories (bind()
,createSubcontext()
methods that accept attributes as arguments). To keep these operations and haveDirObject
at the same time would produce the need for a third interface (perhaps calledDirContext
) to contain just these hybrids.Furthermore, having
DirContext
instead ofDirObject
is somewhat more convenient in that you can perform some operations in one step instead of two. For exampleDirContext.getAttributes()
could be used to get the attributes associated with a named object, whereas withDirObject
, you would need first to resolve to the object (Context.lookup()
) and then useDirObject.getAttributes()
to get the attributes from it.
The
DirContext
interface contains support for schemas. For example, from aDirContext
object you can obtain its schema object, which points to the directory space where the schema for this particularDirContext
instance is defined. From aDirContext
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 theAttribute
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 inDirContext
are flexible enough that these different levels of support for schemas can be accommodated.
For each method in the
Context
andDirContext
interfaces that accepts aName
argument, there is a corresponding overloaded form that accepts aString
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 aName
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 withName
objects rather than string names. For these applications, we provide theName
-based methods in the context interfaces. Not providing these methods would probably cause proliferation ofName
-like interfaces/classes to support manipulation of names in their structural form in applications developed on top of JNDI.
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. AReference
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 theReferenceable
interface, which contains the methodgetReference()
.There is some similarity between the interfaces
Serializable
andReferenceable
and a natural question is "why not just useSerializable
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.
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 oflookup()
to the expected class, instead of calling a separate operation to transform the result oflookup()
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); prt.print(someFileName);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 aReference
into the object identified by theReference
, JNDI encourages different applications and system providers to utilize this mechanism, rather than inventing separate mechanisms on their own.