Naming and directory operations
You can use JNDI to perform the following operations: read operations and update namespace operations. This section describes the two operations:
L Query object
L List the context
L Add, overwrite, and remove bindings
L Renames the object
L Create and destroy subcontexts
configuration
Before you can perform operations in the naming and directory services, you need to get the initialization context — the starting point of the namespace. Because all methods of naming and directory services are executed relative to some context.
To get the initialization context, you must perform the following steps:
1. Select the access provider you want to access.
2. Specify the initialization context.
3. Call the InitialContext constructor.
Step 1: Select the service provider for the initialization context
You can specify the service provider for the initialization context, create a collection of environment variables (Hashtable), and add the name of the service provider to it. Environment properties are covered in detail in the JNDI tutorial.
If you use Sun’s LDAP service provider, the code looks like this:
Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY,”com.sun.jndi.ldap.LdapCtxFactory”); |
To specify Sun’s file system service provider, the code looks like this:
Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY,”com.sun.jndi.fscontext.RefFSContextFactory”); |
You can use some system properties to describe the service provider you use. This is described in detail in the JNDI tutorial.
Step 2: Provide the information needed to initialize the context
Clients of different directories may need to provide different information to connect to the directory. For example, you need to specify the machine on which the server is running and identify the users in the directory. This information is passed to the service provider through environment properties. JNDI specifies the general environment parameters used by the service provider. Your service provider documentation specifies the parameters that need to be provided.
The LDAP provider requires the application to provide the location of the LDAP server, as well as authentication information. To provide this information, the following code is required:
env.put(Context.PROVIDER_URL, “ldap://ldap.wiz.com:389”); env.put(Context.SECURITY_PRINCIPAL, “joeuser”); env.put(Context.SECURITY_CREDENTIALS, “joepassword”); |
Sun’s LDAP service provider is used in this tutorial. In this example, we assume that the server is set up on the local computer, using port 389, and the root identification name is O =JNDITutorial. Authentication is not required to modify the directory. This information is needed to set up the environment.
env.put(Context.PROVIDER_URL, “ldap://localhost:389/o=JNDITutorial”); |
If you use a directory with a different setup, you need to set the appropriate environment properties. You need to replace “localhost” with the machine name. You can run the examples on any public directory server or on your own server on another machine. You need to replace “localhost” with the name of that machine and o=JNDITutorial with the appropriate naming context.
Step 3: Create the initialization context
You have created the initialization context. To do this, you put the environment properties you created earlier into the InitialContext constructor:
Context ctx = new InitialContext(env); |
Now that you have a reference to the context object, you can start accessing the naming service.
To complete the directory operation, you need to use InitialDirContext. To do this, use one of its constructors:
DirContext ctx = new InitialDirContext(env); |
This sentence returns a reference to the DirContext object used for directory operations.
Naming exceptions
Many methods in JNDI packages throw exceptions indicating that the operation request cannot be executed. In general, you’ll see methods that can throw namingExceptions wrapped in try/catch.
try { Context ctx = new InitialContext(); Object obj = ctx.lookup(“somename”); } catch (NamingException e) { // Handle the error System.err.println(e); } |
Exception class structure
JNDI has a rich exception structure, all of which are inherited from the NamingException class. Exception class names are self-explanatory and are listed below.
If you want to handle specific NamingException subclasses, you need to separate catch subclasses. For example, the following code specifically treats AuthenticationException and its subclasses.
try { Context ctx = new InitialContext(); Object obj = ctx.lookup(“somename”); } catch (AuthenticationException e) { // attempt to reacquire the authentication information . } catch (NamingException e) { // Handle the error System.err.println(e); } |
The enumeration
Operations such as context.list () and dirContext.search () return NamingEnumeration. In these cases, if an error occurs and no result is returned, NamingException or one of its subclasses is thrown on method request. If an error occurs and partial results are returned, return NamingEnumeration so you can get those results. When all the results are out, and then request NamingEnumeration. HasMore () can lead to throw NamingException (or its subclasses) abnormalities, says there is an error. In this case, enumerations become illegal and no methods can be requested.
For example, if you execute search() and specify how many results to return at most, search() returns at most N results. If the results more than n, then when the first n + 1 times request NamingEnumeration. HasMore (), throw SizeLimitExceededException. See the sample code for limit in this section.
Examples in this manual
In the online sample code in this manual file, try/catch statements are usually omitted for ease of reading. Typically, because only a portion of the code snippet is shown here, only lines that directly represent concepts are shown. If you look at the source file that accompanies this tutorial, you’ll see the try/catch statement in place.
The exception in the Javax.Naming package can be seen here.
The query object
To query objects from the naming service, use the context.lookup () method and pass in the name of the object you want. Suppose the naming service has an object whose name is CN =Rosanna Lee,ou=People. To get this object, you simply write:
Object obj = ctx.lookup(“cn=Rosanna Lee,ou=People”); |
The type of object returned by lookup() depends on the naming service and the data associated with the object. A naming service can contain many different types of objects, and objects queried in different parts of the system may yield different types. For example, “cn = Rosanna Lee, ou = People” is bound to the context object (javax.mail. Naming. Ldap. LdapContext). You can cast the result of the lookup() method into the desired class.
For example, the following code queries the “cn=Rosanna Lee,ou=People” object and casts the LdapContext.
import javax.naming.ldap.LdapContext; . LdapContext ctx = (LdapContext) ctx.lookup(“cn=Rosanna Lee,ou=People”); |
The complete example is in the lookup.java file.
Querying names in Java SE 6 introduces two new static methods:
l InitialContext.doLookup(Name name)
l InitialContext.doLookup(String name)
These methods provide shortcuts to find objects without instantiating InitialContext.
Enumeration context
Instead of getting one object at a time from context.lookup (), you can list the entire rest of the text in a single operation. There are two methods to enumerate the context: one returns the binding relationship, and the other returns only the name-object type name.
Context.List()methods
Context.list() returns an enumeration of NameClassPair. Each NameClassPair contains the object name and the object type name. The following code lists the contents of the “ou=People” directory (for example, files and directories found in the “ou=People” directory).
NamingEnumeration list = ctx.list(“ou=People”);
while (list.hasMore()) { NameClassPair nc = (NameClassPair)list.next(); System.out.println(nc); } |
The return value is as follows:
# java List cn=Jon Ruiz: javax.naming.directory.DirContext cn=Scott Seligman: javax.naming.directory.DirContext cn=Samuel Clemens: javax.naming.directory.DirContext cn=Rosanna Lee: javax.naming.directory.DirContext cn=Maxine Erlund: javax.naming.directory.DirContext cn=Niels Bohr: javax.naming.directory.DirContext cn=Uri Geller: javax.naming.directory.DirContext cn=Colleen Sullivan: javax.naming.directory.DirContext cn=Vinnie Ryan: javax.naming.directory.DirContext cn=Rod Serling: javax.naming.directory.DirContext cn=Jonathan Wood: javax.naming.directory.DirContext cn=Aravindan Ranganathan: javax.naming.directory.DirContext cn=Ian Anderson: javax.naming.directory.DirContext cn=Lao Tzu: javax.naming.directory.DirContext cn=Don Knuth: javax.naming.directory.DirContext cn=Roger Waters: javax.naming.directory.DirContext cn=Ben Dubin: javax.naming.directory.DirContext cn=Spuds Mackenzie: javax.naming.directory.DirContext cn=John Fowler: javax.naming.directory.DirContext cn=Londo Mollari: javax.naming.directory.DirContext cn=Ted Geisel: javax.naming.directory.DirContext |
Context.listBindings()methods
The context.listbindings () method returns an enumeration of bindings. Binding is a subclass of NameClassPair. Bindings contain not only object names and object class names, but also objects. The following code snippet enumerates the “ou=People” context, printing out each binding name and object.
NamingEnumeration bindings = ctx.listBindings(“ou=People”);
while (bindings.hasMore()) { Binding bd = (Binding)bindings.next(); System.out.println(bd.getName() + “: ” + bd.getObject()); } |
The result is as follows:
# java ListBindings cn=Jon Ruiz: com.sun.jndi.ldap.LdapCtx@1d4c61c cn=Scott Seligman: com.sun.jndi.ldap.LdapCtx@1a626f cn=Samuel Clemens: com.sun.jndi.ldap.LdapCtx@34a1fc cn=Rosanna Lee: com.sun.jndi.ldap.LdapCtx@176c74b cn=Maxine Erlund: com.sun.jndi.ldap.LdapCtx@11b9fb1 cn=Niels Bohr: com.sun.jndi.ldap.LdapCtx@913fe2 cn=Uri Geller: com.sun.jndi.ldap.LdapCtx@12558d6 cn=Colleen Sullivan: com.sun.jndi.ldap.LdapCtx@eb7859 cn=Vinnie Ryan: com.sun.jndi.ldap.LdapCtx@12a54f9 cn=Rod Serling: com.sun.jndi.ldap.LdapCtx@30e280 cn=Jonathan Wood: com.sun.jndi.ldap.LdapCtx@16672d6 cn=Aravindan Ranganathan: com.sun.jndi.ldap.LdapCtx@fd54d6 cn=Ian Anderson: com.sun.jndi.ldap.LdapCtx@1415de6 cn=Lao Tzu: com.sun.jndi.ldap.LdapCtx@7bd9f2 cn=Don Knuth: com.sun.jndi.ldap.LdapCtx@121cc40 cn=Roger Waters: com.sun.jndi.ldap.LdapCtx@443226 cn=Ben Dubin: com.sun.jndi.ldap.LdapCtx@1386000 cn=Spuds Mackenzie: com.sun.jndi.ldap.LdapCtx@26d4f1 cn=John Fowler: com.sun.jndi.ldap.LdapCtx@1662dc8 cn=Londo Mollari: com.sun.jndi.ldap.LdapCtx@147c5fc cn=Ted Geisel: com.sun.jndi.ldap.LdapCtx@3eca90 |
The end of theNamingEnumeration
NamingEnumeration can be terminated in three ways: generic, explicit, and non-explicit.
L when NamingEnumeration. HasMore () returns false, enumerations end terminated at the same time.
You can request the NamingEnumeration. Close () method to explicitly terminate an enumeration before the enumeration is terminated. Doing so prompts the underlying implementation to release any resources associated with enumerations.
L If the hasMore() or next() methods throw any exceptions, the enumeration terminates immediately.
No matter how the enumeration is terminated, once terminated, the enumeration can no longer be used. Calling any method in a terminated enumeration results in inconclusive results.
Why two different approaches?
List () is intended for browse-type applications and returns only the name of the object in context. For example, a browser might list names in context, expecting the user to select one or more displayed names for subsequent actions. These applications generally do not need to access all objects in the context.
ListBindings () is prepared for applications that need to operate in context objects. For example, the backup program needs to perform a “File Stats” operation on all objects in the file directory. Alternatively, a printer administrator program might want to restart all printers in a building. To perform these operations, you need to get all the objects in context. Therefore, it is expedient to return the object as part of the enumeration.
Applications can select List () or listBindings() depending on the type of information they need.
Add, replace, or remove bindings
The Context interface contains methods to add, replace, and delete bindings in the Context.
Add the binding
To add a binding to the Context, context.bind () takes the object type and the object to bind to.
Before continuing: The examples in this tutorial require you to make additional schema changes. You must turn off schema detection for the LDAP server or add a schema that conforms to this tutorial to the server. This work is typically performed by directory server administrators. Look at the course.
// Create the object to be bound Fruit fruit = new Fruit(“orange”);
// Perform the bind ctx.bind(“cn=Favorite Fruit”, fruit); |
This example creates an object of the Fruit class and binds it to the name “cn=Favorite Fruit” in context CTX. If you then query “cn=Favorite Fruit” in CTX, you will get Fruit cash. Note that you need the FruitFactory class to compile the Fruit class.
If you run the example twice, the second time because NameAlreadyBoundException abnormal failure. Because “CN =Favorite Fruit” has been bound. To run the second time without failure, use rebind().
Add or modify bindings
Rebind () is used to add or replace bindings. Its argument list is the same as bind(), but if the name is already bound, it is first unbound and then rebound to the new object.
// Create the object to be bound Fruit fruit = new Fruit(“lemon”);
// Perform the bind ctx.rebind(“cn=Favorite Fruit”, fruit); |
When you run this example, you will replace the bindings already created in the bind() example.
Remove the binding
To remove the binding, use unbind().
// Remove the binding ctx.unbind(“cn=Favorite Fruit”); |
When this example runs, remove bindings created by bind() or unbind().
rename
You use context.rename () to rename objects in Context.
// Rename to Scott S ctx.rename(“cn=Scott Seligman”, “cn=Scott S”); |
This example binds an object bound to “cn=Scott Seligman” to “cn=Scott S”. After the validation object is renamed, the program renames it back to its original name (” cn=Scott Seligman “) as follows:
// Rename back to Scott Seligman ctx.rename(“cn=Scott S”, “cn=Scott Seligman”); |
For more examples of renaming in LDAP, see LDAP advanced Notes.
Create and destroy subcontexts
The Context interface contains the creation and destruction of a subcontext. Subcontexts are contexts that are bound to other contexts.
This example uses an object with attributes and then creates a subcontext in the directory. You can use the methods of DirContext to associate properties and objects when a binding or subcontext is added to a namespace. For example, you can create a Person object and bind it to a namespace while associating attributes with the Person object. Named equals no attributes.
CreateSubcontext () differs from bind() in that it creates a new object, such as a new context to bind to a directory, but bind() binds the given object in the directory.
Create context
To create a naming context, you provide createSubcontext() with the name of the context to create. Attributes to create a context, the DirContext createSubcontext () you want to create the context and need the name of the property.
Before continuing: The examples in this tutorial require you to make additional schema changes. You must turn off schema detection for the LDAP server or add a schema that conforms to this tutorial to the server. This work is typically performed by directory server administrators. Look at the course.
// Create attributes to be associated with the new context Attributes attrs = new BasicAttributes(true); // case-ignore Attribute objclass = new BasicAttribute(“objectclass”); objclass.add(“top”); objclass.add(“organizationalUnit”); attrs.put(objclass);
// Create the context Context result = ctx.createSubcontext(“NewOu”, attrs); |
This example creates a context named “ou=NewO” and has attributes “objectClass”, “top”, and “organizationalUnit”, where “objectClass” has two values.
# java Create ou=Groups: javax.naming.directory.DirContext ou=People: javax.naming.directory.DirContext ou=NewOu: javax.naming.directory.DirContext |
This example creates a new context called “NewOu”, which is a subcontext of CTX.
Destroy context
To destroy the context, supply destroySubcontext() with the name of the context to destroy.
// Destroy the context ctx.destroySubcontext(“NewOu”); |
This example removes the context “NewOu” in context CTX.
The property name
An attribute consists of an attribute identifier and a set of attribute values. An attribute identifier, called an attribute name, is a string representing the attribute. An attribute value is the content of the attribute, and its type is not necessarily a string. When you want to specify get, search, or modify a specified property, you use the property name. The name is also returned in an operation that returns a property (for example, when you perform a read or search operation on a directory).
When using attribute names, you need to know the characteristics of a particular directory server, so you won’t be surprised by the results. These are described in the next subsection.
Attribute types
In directories such as LDAP, the attribute name represents the type of the attribute and is usually called the attribute type name. For example, the attribute name “cn” is also called the attribute type name. Attribute types define the syntax of attribute values, whether multiple values are allowed, equality, and collation rules for comparison and sorting of attribute values.
Attribute subclass
Some directory implementations support directory subtypes, meaning that the server allows property types to be defined using other property types. For example, the “name” attribute might be a supertype for all name-related attributes: “commonName” is a subclass of Name. For directory implementations that support this tesnagar, accessing the “name” property may return the “commonName” property.
When accessing a directory that supports attributes of subtypes, be aware that the server may return a type that does not match your request. To reduce this probability, use the most derived class.
Synonym of attribute name
Some directory implementations support synonyms for attribute names. For example, “cn” might be a synonym for “commonName.” So requesting the cn attribute might return the commonName attribute.
When accessing directories that support attribute synonyms, you must be aware that the server may return a different attribute name than you requested. To prevent this, use the official attribute name instead of using a synonym. The official property name is the property name that defines the property; A synonym is a name in the definition that references the official attribute name.
Language parameter selection
The LDAP V3 extension (RFC 2596) allows you to specify the language encoding along with the attribute name. Like subclass properties, a property name can represent multiple different properties. For example, the “description” attribute has two different language variants:
description: software description; lang-en: software products description; lang-de: Softwareprodukte |
A request for the “Description” property returns all three properties. When accessing a directory that supports this feature, you must be aware that the server may return a different name than it requested.
Reads the properties
To read attributes of an object from the directory, use dirContext.getAttributes () and pass in the name of the attribute you want to read. Suppose the name of an object in the naming service is “cn=Ted Geisel, ou=People”. To get the attributes of an object, use the following code:
Attributes answer = ctx.getAttributes(“cn=Ted Geisel, ou=People”); |
You can print the answer as follows:
for (NamingEnumeration ae = answer.getAll(); ae.hasMore();) { Attribute attr = (Attribute)ae.next(); System.out.println(“attribute: ” + attr.getID()); /* Print each value */ for (NamingEnumeration e = attr.getAll(); e.hasMore(); System.out.println(“value: ” + e.next())) ; } |
The output is as follows:
# java GetattrsAll attribute: sn value: Geisel attribute: objectclass value: top value: person value: organizationalPerson value: inetOrgPerson attribute: jpegphoto value: [B@1dacd78b attribute: mail value: [email protected] attribute: facsimiletelephonenumber value: +1 408 555 2329 attribute: telephonenumber value: +1 408 555 5252 attribute: cn value: Ted Geisel |
Return selected property
To read the properties of the selected subset, you need to provide an array of the property identifiers you want to get.
// Specify the ids of the attributes to return String[] attrIDs = {“sn”, “telephonenumber”, “golfhandicap”, “mail”};
// Get the attributes requested Attributes answer = ctx.getAttributes(“cn=Ted Geisel, ou=People”, attrIDs); |
This example requests the “sn”, “Telephonenumber”, “golfhandicap” and “mail” properties of the object “CN =Ted Geisel, ou=People”, so these three properties are returned in the reply.
Here is the output:
# java Getattrs attribute: sn value: Geisel attribute: mail value: [email protected] attribute: telephonenumber value: +1 408 555 5252 |
Modify the properties
The DirContext interface contains methods to modify the properties and property values of objects in a directory.
Using the Change list
One way to modify an object’s properties is to provide a list of modificationItems. Each ModificationItem contains numeric constants that indicate the type of modification and describe the properties to be modified. Here are the types of modifications.
l ADD_ATTRIBUTE
l REPLACE_ATTRIBUTE
l REMOVE_ATTRIBUTE
Modifications are made to the types provided in the list. Either all changes are made, or none at all.
The following code creates the list of changes. It replaces the value of the “mail” attribute with [email protected], adds value to the “Telephonenumber” attribute, and removes the “jpegPhoto” attribute.
// Specify the changes to make ModificationItem[] mods = new ModificationItem[3];
// Replace the “mail” attribute with a new value mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute(“mail”, “[email protected]”));
// Add an additional value to “telephonenumber” mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute(“telephonenumber”, “+1 555 555 5555”));
// Remove the “jpegphoto” attribute mods[2] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute(“jpegphoto”)); |
Windows Active Directory: Active directory defines the telephonenumber property as a single-valued property, which is inconsistent with RFC 2256. In order for this example to execute in the active directory, you must either replace “telephonenumber” with another attribute or change dirContext.add_attribute to dirContext.replace_attribute.
After creating a list of changes, you can provide modifyAttributes() as follows:
// Perform the requested modifications on the named object ctx.modifyAttributes(name, mods); |
Use the property
Optionally, you can modify the properties by specifying the modification type.
For example, the following line associates the property to be replaced with name in orig:
ctx.modifyAttributes(name, DirContext.REPLACE_ATTRIBUTE, orig); |
The names of other properties remain unchanged.
Both uses of modifyAttributes() are available in the sample application. The program that modifies attributes using the change list restores the original attributes in Part 2 modifyAttributes().
Add and remove bindings with attributes
The named example discusses how to use overloaded versions of the bind() and unbind(), DirContext methods. You use the methods of DirContext to associate the attributes of the object, adding them to the namespace at binding or subcontext time. For example, you might create a Person object and then bind it to a namespace when you associate properties with the Person object.
Add a binding with attributes
Dircontext.bind () is used to add property bindings to the context. It takes the name of the object to bind and a collection of properties.
// Create the object to be bound Fruit fruit = new Fruit(“orange”);
// Create attributes to be associated with the object Attributes attrs = new BasicAttributes(true); // case-ignore Attribute objclass = new BasicAttribute(“objectclass”); objclass.add(“top”); objclass.add(“organizationalUnit”); attrs.put(objclass);
// Perform bind ctx.bind(“ou=favorite, ou=Fruits”, fruit, attrs); |
This example creates the Fruit class object and binds it to the “OU =Fruits” context called “ou=favorite”. The binding has the objectClass property. If you then query “ou=favorite, ou=Fruits” in CTX, you will get a fruit object. If you want to get the “OU =favorite, ou=Fruits” property, you will get the property you just added for the object. Here is the output of the example:
# java Bind orange attribute: objectclass value: top value: organizationalUnit value: javaObject value: javaNamingReference attribute: javaclassname value: Fruit attribute: javafactory value: FruitFactory attribute: javareferenceaddress value: #0#fruit#orange attribute: ou value: favorite |
Display is used more than an attribute to hold some information about the object (Fruit). More on this later.
Twice if you run this example, then the second runtime will fail and throw NameAlreadyBoundException. This is because “ou=favorite” is bound to the context “ou=Fruits”. To succeed, use rebind().
Replace bindings with attributes
Dircontext.rebind () adds or modifies bindings and attributes. It takes the same arguments as bind(). However, if the name already exists with rebind(), new objects and properties will be Unbind first and then bound.
// Create the object to be bound Fruit fruit = new Fruit(“lemon”);
// Create attributes to be associated with the object Attributes attrs = new BasicAttributes(true); // case-ignore Attribute objclass = new BasicAttribute(“objectclass”); objclass.add(“top”); objclass.add(“organizationalUnit”); attrs.put(objclass);
// Perform bind ctx.rebind(“ou=favorite, ou=Fruits”, fruit, attrs); |
When you run this example, it replaces the binding relationship created in the bind() example.
# java Rebind lemon attribute: objectclass value: top value: organizationalUnit value: javaObject value: javaNamingReference attribute: javaclassname value: Fruit attribute: javafactory value: FruitFactory attribute: javareferenceaddress value: #0#fruit#lemon attribute: ou value: favorite |
search
The most useful benefit that directories provide is the yellow Pages feature, or search service. You can compose a query that contains the attributes of the item and then submit the query to the directory. The directory then returns a list of items that satisfy the query. For example, you could go to the directory and look up entries with bowling averages greater than 200, or all people whose last names begin with “Sch.”
The DirContext interface provides methods for querying items that are complex and powerful. The different aspects of searching directories are described in the following sections:
L Basic search
L Search filter
L Search control
Basic search
The simplest queries require you to specify the set of attributes that the entry must contain and the target context for the query.
The following code creates a collection of attributes matchAttrs with two attributes “sn” and “mail”. Table name search entries must have the last name (SN) attribute, which has a value of “Geisel”, and the “mail” attribute, which can be any value. Dircontext.search () is then called to search for entries matching matchAttrs in the context “ou=People”.
// Specify the attributes to match // Ask for objects that has a surname (“sn”) attribute with // the value “Geisel” and the “mail” attribute Attributes matchAttrs = new BasicAttributes(true); // ignore attribute name case matchAttrs.put(new BasicAttribute(“sn”, “Geisel”)); matchAttrs.put(new BasicAttribute(“mail”));
// Search for objects that have those matching attributes NamingEnumeration answer = ctx.search(“ou=People”, matchAttrs);
You can then print the results as follows. while (answer.hasMore()) { SearchResult sr = (SearchResult)answer.next(); System.out.println(“>>>” + sr.getName()); printAttrs(sr.getAttributes()); } |
The printAttrs() method is similar to the getAttributes() method to print a collection of attributes.
The result is as follows:
# java SearchRetAll >>>cn=Ted Geisel attribute: sn value: Geisel attribute: objectclass value: top value: person value: organizationalPerson value: inetOrgPerson attribute: jpegphoto value: [B@1dacd78b attribute: mail value: [email protected] attribute: facsimiletelephonenumber value: +1 408 555 2329 attribute: cn value: Ted Geisel attribute: telephonenumber value: +1 408 555 5252 |
Return selected property
The previous example returns all attributes of entries that meet the specified query criteria. You can select the attributes you want to include in the result set by passing an array of attribute identifiers to search(). Before creating matchAttrs only, you should create an array of attribute identifiers as follows:
// Specify the ids of the attributes to return String[] attrIDs = {“sn”, “telephonenumber”, “golfhandicap”, “mail”};
// Search for objects that have those matching attributes NamingEnumeration answer = ctx.search(“ou=People”, matchAttrs, attrIDs); |
This example returns the attributes “SN”, “Telephonenumber”, “golfhandicap”, and “mail”, where the entry has the attribute “mail” and the value of the “sn” attribute is “Geisel”. This example produces the following results. (There is no “golfhandicap” attribute in the entry, so there is no return).
# java Search >>>cn=Ted Geisel attribute: sn value: Geisel attribute: mail value: [email protected] attribute: telephonenumber value: +1 408 555 5252 |
The filter
In addition to searching with a specified set of attributes, you can search in the form of a search filter. A search filter is a logical expression for searching. The syntax for acceptable filters for dirContext.search () is defined in RFC 2254.
The following search filter specifies that entries that satisfy the query criteria must have an “sn” attribute with a value of “Geisel” and an arbitrary “mail” attribute:
(&(sn=Geisel)(mail=*)) |
The following code creates the filter and the default SearchControls that you use to execute the query. The results of this query are the same as in the base query.
// Create the default search controls SearchControls ctls = new SearchControls();
// Specify the search filter to match // Ask for objects that have the attribute “sn” == “Geisel” // and the “mail” attribute String filter = “(&(sn=Geisel)(mail=*))”;
// Search for objects using the filter NamingEnumeration answer = ctx.search(“ou=People”, filter, ctls); |
The search results are as follows:
# java SearchWithFilterRetAll >>>cn=Ted Geisel attribute: sn value: Geisel attribute: objectclass value: top value: person value: organizationalPerson value: inetOrgPerson attribute: jpegphoto value: [B@1dacd75e attribute: mail value: [email protected] attribute: facsimiletelephonenumber value: +1 408 555 2329 attribute: cn value: Ted Geisel attribute: telephonenumber value: +1 408 555 5252 |
searchThe filterSyntax overview
A search filter is a search expression with a prefix tag (the logical operator precedes the expression). The following table lists the symbols used to create filters.
symbol |
describe |
& |
And (all items in the list must be true) |
| |
Or (at least one of the lists must be true) |
! |
Not (the inverted term cannot be true) |
= |
Equality (according to matching rules for attributes) |
~ = |
Approximately equal to (according to the matching rules of the attribute) |
> = |
Greater than (according to the matching rules of the attribute) |
< = |
Less than (according to the matching rules of the attribute) |
= * |
Exists (this attribute must be present in the entry, but the value is not limited) |
* |
Wildcard (indicating that the position can have one or more characters), used when specifying attribute values |
\ |
Escape characters (when encountered with “*”, “(“,”) “) |
Each entry in the filter consists of an attribute identifier and an attribute value or symbol representing the attribute value. For example, sn=Geisel indicates that the sn attribute value must be Geisel, and mail=* indicates that the mail attribute must exist.
Each item must be enclosed within parentheses, for example, “(sn=Geisel)”. These items use logical operators such as & to create logical expressions such as “(& (sn=Geisel) (mail=*))”.
Each logical expression can be further of other items, such as “(| (& (sn = Geisel) (mail = *)) (sn = L *))”. This example requests either an “sn” attribute with a value of “Geisel” and a “mail” attribute or an “sn” attribute starting with the letter “L”.
Refer to RFC 2254 for a detailed description of the syntax.
Return selected property
The previous example returns all attributes in the entry that satisfy the specified filter. You can select the return property by setting the search control parameters. You create want to include in the result set the properties in the identifier, and then he passed to the SearchControls. SetReturningAttributes (). As follows:
// Specify the ids of the attributes to return String[] attrIDs = {“sn”, “telephonenumber”, “golfhandicap”, “mail”}; SearchControls ctls = new SearchControls(); ctls.setReturningAttributes(attrIDs); |
This example is consistent with the results in the basic search section that returns selected properties. The result is as follows. (This entry does not have a “golfhandicap” attribute, so it is not returned).
# java SearchWithFilter >>>cn=Ted Geisel attribute: sn value: Geisel attribute: mail value: [email protected] attribute: telephonenumber value: +1 408 555 5252 |
The scope of
The default SearchControls specifies that searches only take place in the namespace (searchControls.onelevel_scope). This default option is used in the search filters section.
In addition to the default option, you can specify that the search is performed in the entire subtree or only in the named object.
Search subtree
A search of the entire subtree searches not only for the named object but also for its descendants. To make a search in this way, to the SearchControls. According to the following way setSearchScope () passed in the SearchControls. SUBTREE_SCOPE parameters:
// Specify the ids of the attributes to return String[] attrIDs = {“sn”, “telephonenumber”, “golfhandicap”, “mail”}; SearchControls ctls = new SearchControls(); ctls.setReturningAttributes(attrIDs); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// Specify the search filter to match // Ask for objects that have the attribute “sn” == “Geisel” // and the “mail” attribute String filter = “(&(sn=Geisel)(mail=*))”;
// Search the subtree for objects by using the filter NamingEnumeration answer = ctx.search(“”, filter, ctls); |
This example searches the subtree of the CTX context to get the entries that satisfy the search filter. It finds the “CN = Ted Geisel, ou=People” entry in the subtree that satisfies the filter.
# java SearchSubtree >>>cn=Ted Geisel, ou=People attribute: sn value: Geisel attribute: mail value: [email protected] attribute: telephonenumber value: +1 408 555 5252 |
Searching for named objects
You can also search for named objects. This can be useful, for example, to test whether a named object satisfies a search filter. To search for named objects, pass searchcontrols.object_scope to setSearchScope().
// Specify the ids of the attributes to return String[] attrIDs = {“sn”, “telephonenumber”, “golfhandicap”, “mail”}; SearchControls ctls = new SearchControls(); ctls.setReturningAttributes(attrIDs); ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
// Specify the search filter to match // Ask for objects that have the attribute “sn” == “Geisel” // and the “mail” attribute String filter = “(&(sn=Geisel)(mail=*))”;
// Search the subtree for objects by using the filter NamingEnumeration answer = ctx.search(“cn=Ted Geisel, ou=People”, filter, ctls); |
This example tests whether the object “cn=Ted Geisel, ou=People” satisfies the given filter.
# java SearchObject >>> attribute: sn value: Geisel attribute: mail value: [email protected] attribute: telephonenumber value: +1 408 555 5252 |
The example finds a result and prints it. Notice that the name field in the result is empty. Because the name of the object is the context in which the query is performed (cn=Ted Geisel, ou=People).
Results the number of
Sometimes, queries may return too many results and you want to limit the size of the result set. At this point you can use a limited number of search controls. By default, there is no limit to the number of searches — it will return all the results it finds. To set up the number of search is limited, passing the figures to the SearchControls. SetCountLimit ().
The following example sets the limit to 1.
// Set the search controls to limit the count to 1 SearchControls ctls = new SearchControls(); ctls.setCountLimit(1); |
If the program trying to get more results, then throws SizeLimitExceededException. If the program sets a number limit, then either treat this exception differently from the NamingExceptions exception or do not request more than the number of results according to the number limit.
Meeting the number of searches is one way to control the resources consumed by the program (such as memory and network bandwidth). Other ways to control resources are to use as small a search filter as possible, start the search in the appropriate context, and use the appropriate scope.
The time limit
The search time limit is the upper limit of how long a search operation can wait for a reply. This is useful when you don’t want to wait too long for an answer. If the search operation more than time limit haven’t finished, so will be thrown TimeLimitExceededException anomalies.
In order to set the time limit, the search will be milliseconds passed to the SearchControls. SetTimeLimit (). The following example sets the time limit to 1 second.
// Set the search controls to limit the time to 1 second (1000 ms) SearchControls ctls = new SearchControls(); ctls.setTimeLimit(1000); |
To make this example run out of time, you need to either reconfigure, use a slow server or use a server with many entries. There are other ways you can make searches longer than one second.
A time limit of 0 means that no time limit is applied, so the request will wait indefinitely.
Frequently asked Questions
The main problems you may encounter when running a successfully compiled program using JNDI classes are as follows:
L has no initialization context
L The connection was rejected
L Connection failure
L Program hangs
L Name not found
L Cannot connect to any host
L Access system attributes cannot be configured
L The CRAM-MD5 authentication cannot be used
1. Get NoInitialContextException
Cause: You did not specify the initialization context to use. In particular, the context.initial_context_factory environment variable is not set to the factory class name of the initialization Context. The latter, could not find the service provider available for the context.initial_Context_factory configuration.
Solution: Set the environment variable context.initial_context_factory to the initialization Context class name you use. For details, see the configuration section.
If the properties are set, make sure the class name is correct and that the class is visible in your program (either in your classpath or in the JRE /lib/ext directory). The Java platform includes service providers with LDAP, COS naming, DNS and RMI registration. All other service providers must be installed and added to the execution environment.
2. “CommunicationException” is displayed, indicating “Connection rejected”.
Cause: The server and port represented by the Context.PROVIDER_URL environment parameter do not provide access. Someone may have disabled or shut down the service. Or you entered the wrong server name or port number.
Solution: Check that services are actually running on the ports and restart the server if necessary. This check depends on the LDAP server you are using. Typically, servers can be managed using an administrative console or tools. You can use the tool to confirm the status of the server.
3. The LDAP server responds to other tools (such as the administrative console) but does not respond to requests from your program.
Cause: The server did not reply the LDAP V3 connection to the full backlight bulb. Some servers (especially public servers) do not respond correctly to LDAP V3, using ignore instead of reject. Also, some LDAP V3 servers have error handling mechanisms, and Sun’s LDAP service provider automatically sends and usually returns server-specific error codes.
Solution: Set the environment parameter java.naming.ldap.version to 2. By default, the LDAP service provider tries to connect to the LDAP server using LDAP V3 and then using LDAP V2. If the server silently ignores v3’s request, the provider assumes that the request is valid. With such a server, you must explicitly set the protocol version to ensure that the server behaves correctly.
If the server is v3, try setting these environment parameters before creating the initialization context:
env.put(Context.REFERRAL, “throw”); |
This turns off the control of automatic sending by the LDAP provider (see the JNDI tutorial for more information).
4. The program hangs.
Reason: The server (especially a public one) does not respond (not a failed reply) when you try to perform a verification that produces too many results or requires the server to query too many entries to produce results. The server tries to reduce resource consumption by calculating costs based on pre-requests.
Alternatively, you try to use secure Socket Layer (SSL) but the server/port does not support it, or vice versa (you try to talk to the SSL port using a normal socket).
Eventually, the server either responds very slowly due to load or does not respond at all to some requests.
Solution: If the application is suspended because the server is trying to reduce resource consumption, retry requests will get a single reply or very few replies. This will help you determine if the server is still active. This way, you can widen the original query and resend it.
If your program hangs because of SSL problems, you need to find the SSL port and set the context.security_protocol environment parameter correctly. If the port is an SSL port, this parameter should be set to SSL. This parameter should not be set if it is not an SSL port.
If the program is not for the reason hangs, using com. Sun. Jndi. Ldap. Read. Read timeout timeout. The value of this parameter is a string representing the number of milliseconds that the LDAP request read timed out. If the LDAP provider does not get a response within the period, the read attempt is aborted. The number should be greater than 0. Equal to or less than 0 indicates that no read timeout is specified and is equal to waiting indefinitely for a reply.
If this parameter is not specified, by default it waits until a reply is received.
Such as:
env.put(“com.sun.jndi.ldap.read.timeout”, “5000”); |
Indicates that if the LDAP server does not respond within 5 seconds, the read request will be abandoned.
5. You get NameNotFoundException exception.
Reason: The root identification name is provided when you initialize the initial context for LDAP. For example, if you set context.provider_URL to “ldap:// LDapServer :389/o=JNDITutorial” for the initial Context and then provide the name “CN =Joe,c=us”, Then the full name you pass to the LDAP service is “CN =Joe, C =us, O =JNDITutorial”. If this is indeed the name you want, you should verify that the server contains the entry.
Also, the Sun Java directory server returns an error if you provide an incorrect identification name during authentication. For example, if you set the context.security_principal environment parameter to “cn=Admin, o=Tutorial” and “cn=Admin, o=Tutorial” is not an entry for the LDAP server, The LDAP provider will throw a NameNotFoundException. The Sun Java directory server is actually returning some authentication exceptions, not “Name not found.”
Solution: Make sure the name you provide exists on the server. You can verify this by enumerating all the entries in the parent context or by using other tools such as the server’s administrator console.
The following are the problems you may encounter when deploying applets.
6. Your applet gets an AppletSecurityException when it tries to connect to the directory server. The server is running on a different machine than the one on which the applet was downloaded.
Reason: The applet is not signed, so it can only connect to the machine from which it was loaded. Alternatively, if appet has been signed, the browser does not grant the applet permission to connect to the directory server.
Solution: If you want to allow an applet to connect to a directory server on any machine, you need to sign the entire applet along with the JNDI JAR used by the applet. For signing jars, see Signing and Verifying JAR files.
7. An AppletSecurityException occurs when your applet attempts to set environment properties using system properties.
Cause: The browser restricts access to system parameters and throws a SecurityException when you try to read.
Solution: If you need input for an applet, try using applet Params instead.
8. Throw an AppletSecurityException when the applet runs in Firefox and tries to authenticate LDAP with CRAM-MD5.
Reason: Firefox prevents access to the java.security package. The LDAP provider USES Java. Security. MessageDigest the information provided in this paper, the function to achieve CRAM – MD5.
Solution: Use a Java plug-in.