h2. Dn A *Dn* (*D{*}istinguished *N{*}ame) represent a path in the *DiT*. Like *URL* names, it has to be read from right to left. For instance, the *{_}directory.apache.org{_}* name has the most generic part on the right (*org*), then a more specific part in the middle (*apache*) and the most specific part on the left (*directory*). *Dn{*}s work the exact same way, except that we use a comma (',') to separate the parts : *{_}dc=directory,ou=apache,ou=org{_}* Each part of a *Dn* is a *[DIRAPI:Rdn]* (*R{*}elative *D{*}Istinguished *N{*}ame, because it's relative to its parent's *Dn*). In the previous example (*{_}dc=directory,ou=apache,ou=org{_}*), the leftmost part is the *[DIRAPI:Rdn]* (*{_}dc=directory{_}*), the right most part is itself a *Dn* (*{_}ou=apache,ou=org{_}*) In other words, we can describe a hierarchy using *Dn{*}s, a bit like *Unix* paths describe the content of a file system. {tip:title=Info} The Dn class is immutable. {tip} h3. Schema awareness *Dn* are composed of *[DIRAPI:Rdn]{*}s, themselves composed of *[DIRAPI:Ava]{*}s (see the respective chapter about those elements). Base line, an *[DIRAPI:Ava]* is a *[AttributeType (...)]* and a *[DIRAPI:Value]*. *LDAP* defines a set of *[AttributeType (...)]{*}s which can be accepted by a Server, and as *Dn* are composed of *[DIRAPI:Ava]{*}s, they are constrained to accept only valid *[AttributeType (...)]{*}s. That mean we may want to make the *Dn* schema aware, in order to check that the given *[AttributeType (...)]* are valid. This can be done by passing a *[SchemaManager (...)]* to the *Dn* when creating one. Note that you may not have access to the *[SchemaManager (...)]* associated with the *LDAP* server you are working with (either because it can't provide one, or because you have no idea about what kind of *[AttributeType (...)]{*}s the server provides). This is only an issue if you don't know what kind of *Dn{*}s are acceptable by the server, otherwise you can construct schema agnostic *Dn{*}s and send them to the server, it will do the check anyway. The only big issue when you work with schema agnostic *Dn* is that comparing two *Dn{*}s may be complicated. h3. Constructing a DN There are many ways to construct a *Dn*. We can pass a string representation of a *Dn* and get back a *Dn* instance, or concatenate a *[DIRAPI:Rdn]* to an existing *Dn*, or concatenate a list of *[DIRAPI:Rdn]{*}s. Let's create some *Dn* now : h5. Creating an Empty Dn Here are four ways you can use to create an empty *Dn*, the last one being schema aware : {code:java} @Test public void testCreateDn() { // Create an empty DN Dn dn = new Dn(); // Same thing, using a constant Dn emptyDn = Dn.EMPTY_DN; // The RootDSE Dn rootDSE = Dn.ROOT_DSE; // A Schema Aware empty Dn Dn dnSchema = new Dn( schemaManager ); assertEquals( dn, emptyDn ); assertEquals( dn, rootDSE ); assertEquals( emptyDn, rootDSE ); assertEquals( dn, dnSchema ); } {code} h5. Creating a schema agnostic Dn There are basically three ways to create a *Dn*. The first one is to pass a String representing the *Dn* : {code:java} ... // Create a DN Dn dn1 = new Dn( "dc=example, dc=com" ); ... {code} Note that you can also pass more than one string, constructing your *Dn* using variable for instance, like in : {code:java} @Test public void testCreateDn4() throws LdapInvalidDnException { // Create a DN Dn dn1 = new Dn( "dc=test, dc=example, dc=com" ); String name = "test"; // Same thing, using a list of Strings Dn dn2 = new Dn( "dc", name, "dc=example, dc=com" ); assertEquals( dn1, dn2 ); } {code} If one of the String does not contain an '=' sign, then it means the parser will consider that the next String is the value. This can be very convenient in some cases. (what happens is that the constructor first concatenates all the String in one single String, and parse it to produce a *Dn*) The second way is to pass a list of *[DIRAPI:Rdn]s* : {code:java} @Test public void testCreateDn() throws LdapInvalidDnException { Dn dn1 = new Dn( "dc=example, dc=com" ); Rdn example = new Rdn( "dc=example" ); Rdn com = new Rdn( "dc=com" ); // Create a DN Dn dn2 = new Dn( example, com ); assertEquals( dn1, dn ); } {code} Note that the order in which the *[DIRAPI:Rdn]s* are passed is the same as the order you'll find them in the resulting *Dn* The third way is to concatenate a *[DIRAPI:Rdn]* with an existig *Dn* : {code:java} @Test public void testCreateDn() throws LdapInvalidDnException { Dn dn1 = new Dn( "dc=test, dc=example, dc=com" ); Rdn test = new Rdn( "dc=test" ); Rdn baseDn = new Dn( "dc=example, dc=com" ); // Create a DN Dn dn2 = new Dn( example, baseDn ); assertEquals( dn1, dn ); } {code} h4. Schema aware DN construction This is just a note that all the described constructor can take an extra parameter : a reference to a *[SchemaManager (...)]* instance, to construct Schema Aware *Dn*. Here are some combined examples : {code:java} @Test public void testCreateDnSchemaAware() throws Exception { SchemaManager schemaManager = new DefaultSchemaManager(); // Create some schema aware DN Dn dn1 = new Dn( schemaManager, "sn=john doe, dc=example, dc=org" ); Dn dn2 = new Dn( new Rdn( "sn=John Doe" ), new Dn( schemaManager, "dc=example, dc=org" ) ); Dn dn3 = new Dn( schemaManager, "2.5.4.4 = John Doe ", "dc", "example", "dc=org" ); Dn dn4 = new Dn( schemaManager, "SN=JOHN DOE, dc=example, dc=org" ); assertEquals( dn1, dn2 ); assertEquals( dn1, dn3 ); assertEquals( dn1, dn4 ); assertEquals( dn2, dn3 ); assertEquals( dn2, dn4 ); assertEquals( dn3, dn4 ); } {code} h3. Basic manipulations on a DN There are a few methods that can be used on a *Dn* to get a part of it or to extend it. Let's describe each of these methods. h5. add( String ) and add( Rdn ) These two methods are used to construct a new *Dn* from an existing one, by adding a *[DIRAPI:Rdn]* to it. It's important to remember that the *Dn* class is immutable, and that those two methods return a _*new{*}_ *Dn*, the original one being unmodified. {code:java} @Test public void testAddString() throws Exception { Dn dn = new Dn( "ou=apache, dc=org" ); Dn dn2 = dn.add( "dc=directory" ); assertEquals( "ou=apache, dc=org", dn.getName() ); assertEquals( "dc=directory,ou=apache, dc=org", dn2.getName() ); Dn dn3 = dn.add( new Rdn( "dc=mina" ) ); assertEquals( "ou=apache, dc=org", dn.getName() ); assertEquals( "dc=mina,ou=apache, dc=org", dn3.getName() ); } {code} h5. add( Dn ) Does pretty much the same that the _add( Rdn )_ method, but taking a *Dn* as an argument. It's used to concatenate two *Dn* together. Again, it creates a new *Dn. h5. applySchemaManager( SchemaManager ) Make the *Dn* schema aware. It will also normalize the *Dn*, transforming the *[AttributeType (...)]*s to *[DIRAPI:Oid]*s and normalize the *[DIRAPI:Value]*s. here is an example : {code:java} @Test public void testApplySchemaManager() throws Exception { Dn dn = new Dn( "OU=Apache, OU=org" ); assertEquals( "OU=Apache, OU=org", dn.getName() ); assertEquals( "ou=Apache,ou=org", dn.getNormName() ); dn.applySchemaManager( schemaManager ); assertEquals( "OU=Apache, OU=org", dn.getName() ); assertEquals( "2.5.4.11=apache,2.5.4.11=org", dn.getNormName() ); } {code} h5. getParent(), getRdn() The first method returns the right part of a *Dn*, ie the *Dn* minus its *[DIRAPI:Rdn]*. The second method returns the *[DIRAPI:Rdn]*. Note that if the *Dn* is either empty, null or contains only one *[DIRAPI:Rdn]*, those methods always returns a valid *Dn* or *[DIRAPI:Rdn]*. The returned element just be empty. This example demonstrates how those methods work : {code:java} @Test public void testGetRdn() throws Exception { Dn dn = new Dn( "dc=directory,dc=Apache,dc=org" ); assertEquals( "dc=Apache,dc=org", dn.getParent().getName() ); assertEquals( "dc=directory", dn.getRdn().getName() ); Dn singleDn = new Dn( "dc=org" ); assertEquals( "", singleDn.getParent().getName() ); assertEquals( "dc=org", singleDn.getRdn().getName() ); Dn emptyDn = Dn.EMPTY_DN; assertEquals( "", emptyDn.getParent().getName() ); assertEquals( "", emptyDn.getRdn().getName() ); } {code} h5. getRdn( int ) This is a method that might be useful in some specific cases. It allows you to get a *[DIRAPI:Rdn]* in a *Dn*, specifying a position. Note that the *Dn* is containing an list of 0-indexed, left to right *[DIRAPI:Rdn]*s. Here is an example : {code:java} @Test public void testGetRdnAtPos() throws Exception { Dn dn = new Dn( "dc=directory,dc=Apache,dc=org" ); assertEquals( "dc=directory", dn.getRdn(0).getName() ); assertEquals( "dc=Apache", dn.getRdn(1).getName() ); assertEquals( "dc=org", dn.getRdn(2).getName() ); } {code} h5. getRdns() Gets an 0-indexed, left to right, list of *[DIRAPI:Rdn]*s from a *Dn*. {code:java} @Test public void testGetRdns() throws Exception { Dn dn = new Dn( "dc=directory,dc=Apache,dc=org" ); assertEquals( "dc=directory", dn.getRdns().get( 0 ).getName() ); assertEquals( "dc=Apache", dn.getRdns().get( 1 ).getName() ); assertEquals( "dc=org", dn.getRdns().get( 2 ).getName() ); } {code} h5. iterator() A convenient way to iterate through *[DIRAPI:Rdn]{*}s is to use the _iterator()_ method. It walks through each *[DIRAPI:Rdn]*, from left to right. {warning} Contrarely to the getRdn( int ) method, an iterator get through the Rdn from right to left. {warning} Here is an example using this method : {code:java} @Test public void testIterator() throws Exception { Dn dn = new Dn( "dc=directory,dc=Apache,dc=org" ); String[] expected = new String[]{ "dc=org", "dc=Apache", "dc=directory" }; int pos = 0; for ( Rdn rdn : dn ) { assertEquals( expected[pos++], rdn.getName() ); } } {code} h3. Comparing DNs One very important operation done on *Dn* which leads to many problems from the user side is the comparison of *Dn*s. The issue is that when comparing *Dn*s, we process each *[DIRAPI:Rdn]* one by one, and for that we compare each *[DIRAPI:Ava]*. But a user provided *[DIRAPI:Ava]s* *[DIRAPI:Value]* may be different from another one when looking at them as Strings, and be equals when normalized using the *[AttributeType (...)]*'s *[MatchingRule (e)]*. In other words, unless the *Dn* is normalized, one has to do the normalizing himself on the client side. This is *very* inconvenient, and this is the reason we made the API Schema aware. When a *Dn* is Schema aware, comparing it with another *Dn* is just a breeze. The following example demonstrates this : {code:java} @Test public void testEquals() throws Exception { Dn dn1 = new Dn( "dc=directory project,dc=Apache,dc=org" ); Dn dn2 = new Dn( "DC=Directory project,dc=Apache,dc=org" ); Dn dn3 = new Dn( " DC = directory project,dc=Apache,dc=org" ); // Just because the value isn't normalized, the first test fails assertFalse( dn1.equals( dn2 ) ); // Now, the AttributeType has spaces and is upper cased, but as the values are the same // it's ok assertTrue( dn1.equals( dn3 ) ); // Let's check with Schema Aware Dns now dn1.applySchemaManager( schemaManager ); dn2.applySchemaManager( schemaManager ); dn3.applySchemaManager( schemaManager ); assertTrue( dn1.equals( dn2 ) ); assertTrue( dn1.equals( dn3 ) ); // One last check Dn dn4 = new Dn( schemaManager, " 0.9.2342.19200300.100.1.25 = Directory PROJECT , DomainComponent = apache, Dc = ORG " ); assertTrue( dn1.equals( dn4 ) ); } {code} The last check is quite impressive... :) h3. Miscellaneous methods The API offers a few other methods. Some of them are useful to discover the relation between two *Dn{*}s, some other provide an information about the *Dn* itself : h5. isSchemaAware() Tells if the current *Dn* has some knowledge about a *[SchemaManager (...)]*. This is the case if it was created with a *[SchemaManager (...)]*. Here is some code that demonstrates the usage of this method : {code:java} @Test public void testIsSchemaAware() throws Exception { Dn dn1 = new Dn( schemaManager, "dc=directory,dc=apache,dc=org" ); Dn dn2 = new Dn( "dc=directory,dc=apache,dc=org" ); assertTrue( dn1.isSchemaAware() ); assertFalse( dn2.isSchemaAware() ); } {code} h5. isNullOrEmpty( Dn ) Sometimes, it's important to check that a *Dn* is either null or empty, before trying to call a method on a null object. One can use this static method for that purpose. h5. isValid( Dn ) This static method allows a user to check that a String *Dn* is valid, or not. It does not throw an exception, it just parses the *Dn* and return the result as a boolean. Don't overuse it, it's a costly method if you intend to transform this String *Dn* to a normal *Dn*, as you will just parse the *Dn* twice... h5. isRootDSE() and isEmpty() Tells if the *Dn* is empty, or if it's the RootDSE. In fact, both methods do the exact same thing, but the _isRootDSE_ method carries some semantic. Here are some examples : {code:java} @Test public void testIsRootDSE() throws Exception { Dn dn1 = new Dn(); Dn dn2 = new Dn( schemaManager ); Dn dn3 = new Dn( "" ); Dn dn4 = new Dn( "dc=apache, dc=org" ); assertTrue( dn1.isRootDSE() ); assertTrue( dn1.isEmpty() ); assertTrue( dn2.isRootDSE() ); assertTrue( dn2.isEmpty() ); assertTrue( dn3.isRootDSE() ); assertTrue( dn3.isEmpty() ); assertFalse( dn4.isRootDSE() ); assertFalse( dn4.isEmpty() ); } {code} h5. isAncestorOf( Dn ) Checks if the current *Dn* is an ancestor of the given *Dn*. For instance : {code:java} @Test public void testIsAncestorOfSchemaAware() throws Exception { Dn dn = new Dn( schemaManager, "dc=directory,dc=apache,dc=org" ); Dn dnApache = new Dn( schemaManager, "0.9.2342.19200300.100.1.25= APACHE ,dc=org" ); Dn dnOrg = new Dn( schemaManager, "DC = Org" ); Dn dnRoot = new Dn( schemaManager, "" ); Dn dnOther = new Dn( schemaManager, "dc=example,dc=com" ); assertTrue( dn.isAncestorOf( dn ) ); assertTrue( dnApache.isAncestorOf( dn ) ); assertTrue( dnOrg.isAncestorOf( dn ) ); assertTrue( dnRoot.isAncestorOf( dn ) ); assertFalse( dnOther.isAncestorOf( dn ) ); } {code} One can notice that we can compare *Dn* which are using *[DIRAPI:Oid]*{*}s* or a upper case characters without any problem when the *Dns* are schema aware. The same code using schema agnostic *Dns* is a bit more limited : {code:java} @Test public void testIsAncestorOfSchemaAware() throws Exception { Dn dn = new Dn( "dc=directory,dc=apache,dc=org" ); Dn dnApache = new Dn( "dc=apache,dc=org" ); Dn dnOrg = new Dn( "DC=org" ); Dn dnOrgOid = new Dn( "0.9.2342.19200300.100.1.25=org" ); Dn dnRoot = new Dn( "" ); Dn dnOther = new Dn( "dc=example,dc=com" ); assertTrue( dn.isAncestorOf( dn ) ); assertTrue( dnApache.isAncestorOf( dn ) ); assertTrue( dnOrg.isAncestorOf( dn ) ); assertTrue( dnRoot.isAncestorOf( dn ) ); assertFalse( dnOther.isAncestorOf( dn ) ); // Here, we try with an Oid, but it won't work assertFalse( dnOrgOid.isAncestorOf( dn ) ); } {code} h5. getAncestorOf( Dn ) This method is used to get the right part of a *Dn* when we have the right part of it. An example will help you to understand what it's all about : {code:java} @Test public void testGetAncestorOfSchemaAware() throws Exception { Dn dn = new Dn( schemaManager, "dc=directory,dc=apache,dc=org" ); Dn dnApache = new Dn( schemaManager, "DC= APACHE ,dc=org" ); assertEquals( dnApache, dn.getAncestorOf( "DC=directory" ) ); } {code} h5. isDescendantOf( Dn ) This method can be used to know if a *Dn* as the given *Dn* as a parent. Again, an example will be more explicit : {code:java} @Test public void testIsDescendantOfSchemaAware() throws Exception { Dn dn = new Dn( schemaManager, "dc=directory,dc=apache,dc=org" ); assertTrue( dn.isDescendantOf( "dc=apache,dc=org" ) ); } {code} h5. getDescendantOf( Dn ) This method can be used to get the part od the *Dn* which is below a point in the *DiT*. This example will demonstrate the way it works : {code:java} @Test public void testGetDescendantOfSchemaAware() throws Exception { Dn dn = new Dn( schemaManager, "dc=directory,dc=apache,dc=org" ); Dn dnDirectory = new Dn( schemaManager, "dc=directory, dc=apache" ); assertEquals( dnDirectory, dn.getDescendantOf( "0.9.2342.19200300.100.1.25=org" ) ); } {code} h5. getName() and getNormName() Those two methods give back the user provided *Dn* and the normalized *Dn*. The result for the second method differs if the *Dn* is schema aware or not. Let's see with an example : {code:java} @Test public void testGetName() throws Exception { Dn dn1 = new Dn( "Ou = Apache, Ou = ORG" ); Dn dn2 = new Dn( schemaManager, "Ou = Apache, Ou = ORG" ); assertEquals( "Ou = Apache, Ou = ORG", dn1.getName() ); assertEquals( "ou=Apache,ou=ORG", dn1.getNormName() ); assertEquals( "Ou = Apache, Ou = ORG", dn2.getName() ); assertEquals( "2.5.4.11=apache,2.5.4.11=org", dn2.getNormName() ); } {code} h5. getSchemaManager() Simply returns the *[SchemaManager (...)]* associated with the *Dn*, if any. h5. size() Returns the number of *[DIRAPI:Rdn]* contained in the *Dn*.