Previous | Next | Trail Map | Beyond the Basics | What's in a Name?

Composite Names

A composite name is a name that spans multiple naming systems. Here's an example of a composite name:
cn=homedir,cn=Jon Ruiz,ou=People/tutorial/report.txt
It is the string representation of a composite name that contains two parts: an LDAP name, cn=homedir,cn=Jon Ruiz,ou=People, and a file name, tutorial/report.txt. When you pass this string to a Context(in the API reference documentation) method, such as lookup()(in the API reference documentation) , in the namespace set up as recommended by this tutorial (see the Preparations (in the Basics trail) lesson), the method will resolve through the LDAP directory to the file system and return the target object (a file). The mechanics of how this is accomplished by the underlying service provider implementations are described in the Federation (in the Beyond the Basics trail) lesson.

Here's an example:

File f = (File)ctx.lookup(
    "cn=homedir,cn=Jon Ruiz,ou=People/tutorial/report.txt");

String Representation

A composite name is made up of components. You can think of a component as a part of the composite name that belongs to a single naming system. Each component is separated by a slash character (/).

For instance, given the name

cn=homedir,cn=Jon Ruiz,ou=People/tutorial/report.txt
there are three components:
cn=homedir,cn=Jon Ruiz,ou=People
tutorial
report.txt
The first component belongs to the LDAP namespace, while the second two components belong to the file system namespace. As you see from this example, there can be multiple components from the same namespace (tutorial and report.txt are both from the file system namespace), but one component cannot span more than one namespace. (See discussion on this in the Federation (in the Beyond the Basics trail) lesson.)

In addition to the slash character, there are three other special characters in the composite name syntax: the backslash character (\), the single quote character ('), and the double quote character ("). The slash, backslash, and quote characters are referred to as meta characters, which means they have special meaning when they occur in a composite name. The backslash character is the escape character. When the escape character precedes a meta character, the meta character is treated literally and not interpreted according to its special meaning. For example, in the string a\/b, the the slash character is escaped and not treated as a composite name component separator.

The quote characters are provided to allow you use the meta characters within a composite name component without having to escape them. When a component is quoted, its first and last characters must be (the same) quote characters. A single quote must be matched by a single quote; a double quote must be matched by a double quote. Here are three examples of the same component written using escapes and quote characters.

a\/b\/c\/d
"a/b/c/d"
'a/b/b/d'
The reason for allowing two different quote characters is to allow quoting when a quote character already exists in the component. For example, a component with a double quote in it can be represented as either \"ab or '"ab'.

A composite name component can be empty, which means that it contains an empty string. A leading component separator (the composite name string begins with a separator) denotes a leading empty component. A trailing component separator (the composite name string ends with a separator) denotes a trailing empty component. Adjacent component separators denote an empty component. Here are examples of each:

/abc
abc/
abc//xyz

See the discussion later in this lesson about how best to accommodate special characters in a name that conflicts with the JNDI composite name syntax.

The CompositeName Class

The CompositeName(in the API reference documentation) class represents the structural form of a composite name. The constructor(in the API reference documentation) accept a string representation of a composite name and parses it into components according to the composite name syntax. Here's an example that uses the constructor to parse a composite name and then prints out its components:
String name = // composite name to parse
try {
    CompositeName cn = new CompositeName(name);
    System.out.println(cn + " has " + cn.size() + " components: ");
    for (int i = 0; i < cn.size(); i++) {
	System.out.println(cn.get(i));
    }
} catch (InvalidNameException e) {
    System.out.println("Cannot parse name: " + name);
}
Running this example with an input of a/b/c produces the following results:
a/b/c has 3 components: 
a
b
c

The CompositeName class contains methods to access components, to modify and compare a CompositeName, and get the string representation of a CompositeName.

Accessing Components of a Composite Name

get(int posn)(in the API reference documentation)
getAll()(in the API reference documentation)
getPrefix(int posn)(in the API reference documentation)
getSuffix(int posn)(in the API reference documentation)
clone()(in the API reference documentation)

To retrieve the component at a particular position within a CompositeName, you use get(). To see an example of its use, see the constructor example shown above.

getAll() returns all of the components of a CompositeName as an enumeration. You iterate through the enumeration to get each of the components. The constructor example can be rewritten using an enumeration, as show here:

try {
    CompositeName cn = new CompositeName(name);
    System.out.println(cn + " has " + cn.size() + " components: ");
    for (Enumeration all = cn.getAll(); all.hasMoreElements();) {
	System.out.println(all.nextElement());
    }
} catch (InvalidNameException e) {
    System.out.println("Cannot parse name: " + name);
}

You can also get a CompositeName's suffix or prefix as a CompositeName instance. Here's an example that gets the suffix and prefix of a composite name.

CompositeName cn = new CompositeName("one/two/three");
Name suffix = cn.getSuffix(1);  // 1 <= index < cn.size()
Name prefix = cn.getPrefix(1);  // 0 <= index < 1
When you run this program, it generates the following output:
two/three
one
To make a copy of a CompositeName, you use clone().

Modifying a Composite Name

add(String comp)(in the API reference documentation)
add(int posn, String comp)(in the API reference documentation)
addAll(Name comps)(in the API reference documentation)
addAll(Name suffix)(in the API reference documentation)
addAll(int posn, Name suffix)(in the API reference documentation)
remove(int posn)(in the API reference documentation)

After creating a CompositeName instance, you can add and remove components from it. Here's an example that appends a CompositeName to an existing CompositeName, adds components to the front and the end, and removes the second component.

CompositeName cn = new CompositeName("1/2/3");
CompositeName cn2 = new CompositeName("4/5/6");
System.out.println(cn.addAll(cn2));           // 1/2/3/4/5/6
System.out.println(cn.add(0, "abc"));         // abc/1/2/3/4/5/6
System.out.println(cn.add("xyz"));            // abc/1/2/3/4/5/6/xyz
System.out.println(cn.remove(1));             // 1
System.out.println(cn);			      // abc/2/3/4/5/6/xyz

Comparing a Composite Name

compareTo(Object name)(in the API reference documentation)
equals(Object name)(in the API reference documentation)
endsWith(Name name)(in the API reference documentation)
startsWith(Name name)(in the API reference documentation)
isEmpty()(in the API reference documentation)
You can use the compareTo() method to sort a list of CompositeName instances. Here's an example that uses Bubble Sort:
private static void sort(CompositeName[] names) {
    int bound = names.length-1;
    CompositeName tmp;

    while (true) {
        int t = -1;
        for (int j=0; j < bound; j++) {
  	    int c = names[j].compareTo(names[j+1]);
	    if (c > 0) {
		tmp = names[j];
		names[j] = names[j+1];
		names[j+1] = tmp;
		t = j;
	    }
        }
        if (t == -1) break;
	bound = t;
    }
}
You use equals() to see whether two CompositeNames are syntactically equal. Two CompositeNames are equal if they both have the same (case-exact matched) components in the same order. You use startsWith() and endsWith() to see whether a CompositeName starts with or ends with another CompositeName; that is, whether a CompositeName is a suffix or prefix of another CompositeName. You can use the convenience method isEmpty() to see whether a CompositeName has 0 components. You can also use the expression size() == 0 to perform the same check. Here are some examples of using some of these comparison methods:
CompositeName one = new CompositeName("cn=fs/o=JNDITutorial/tmp/a/b/c");
CompositeName two = new CompositeName("tmp/a/b/c");
CompositeName three = new CompositeName("cn=fs/o=JNDITutorial");
CompositeName four = new CompositeName();

System.out.println(one.equals(two)); 	    // false
System.out.println(one.startsWith(three));  // true
System.out.println(one.endsWith(two));      // true
System.out.println(one.startsWith(four));   // true
System.out.println(one.endsWith(four));     // true
System.out.println(one.endsWith(three));    // false
System.out.println(one.isEmpty());	    // false
System.out.println(four.isEmpty());	    // true
System.out.println(four.size() == 0);	    // true

Getting the String Representation

toString()(in the API reference documentation)
When you use the CompositeName constructor, you supply the string representation of a composite name and get back a CompositeName instance. To do the reverse, that is, to get the string representation of a CompositeName instance, you use the toString() method. The result of toString() can be fed back to the constructor to produce a CompositeName instance that is equal to the original CompositeName instance. Here's an example:
CompositeName cn = new CompositeName(name);
String str = cn.toString();
System.out.println(str);
CompositeName cn2 = new CompositeName(str);
System.out.println(cn.equals(cn2));		// true

As Argument to Context Methods

When you pass a CompositeName instance to methods in the Context(in the API reference documentation) and DirContext(in the API reference documentation) interfaces, it is treated as a composite name. Here is an example that looks up an object by first creating a CompositeName instance representing its name:
// Create the initial context
Context ctx = new InitialContext(env);
	
// Parse string name into CompositeName    
Name cname = new CompositeName(
    "cn=homedir,cn=Jon Ruiz,ou=people/tutorial/report.txt");

// Perform lookup using CompositeName
File f = (File) ctx.lookup(cname);


Previous | Next | Trail Map | Beyond the Basics | What's in a Name?