You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2013/06/26 17:56:46 UTC

svn commit: r1496979 - in /directory/apacheds/trunk: server-integ/src/test/java/org/apache/directory/server/operations/modify/ModifyAddIT.java xdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/AbstractBTreePartition.java

Author: elecharny
Date: Wed Jun 26 15:56:46 2013
New Revision: 1496979

URL: http://svn.apache.org/r1496979
Log:
Fixed the modification of null values when doing a modification

Modified:
    directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/modify/ModifyAddIT.java
    directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/AbstractBTreePartition.java

Modified: directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/modify/ModifyAddIT.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/modify/ModifyAddIT.java?rev=1496979&r1=1496978&r2=1496979&view=diff
==============================================================================
--- directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/modify/ModifyAddIT.java (original)
+++ directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/modify/ModifyAddIT.java Wed Jun 26 15:56:46 2013
@@ -27,6 +27,7 @@ import static org.junit.Assert.assertNot
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.io.IOException;
 import java.util.Arrays;
 
 import javax.naming.NamingEnumeration;
@@ -45,9 +46,18 @@ import javax.naming.directory.NoSuchAttr
 import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
 
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.DefaultModification;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
 import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
 import org.apache.directory.api.ldap.model.ldif.LdifUtils;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Strings;
 import org.apache.directory.junit.tools.MultiThreadedMultiInvoker;
+import org.apache.directory.ldap.client.api.LdapConnection;
+import org.apache.directory.ldap.client.api.LdapNetworkConnection;
 import org.apache.directory.server.annotations.CreateLdapServer;
 import org.apache.directory.server.annotations.CreateTransport;
 import org.apache.directory.server.core.annotations.ApplyLdifs;
@@ -94,530 +104,569 @@ transports =
 })
 public class ModifyAddIT extends AbstractLdapTestUnit
 {
-    @Rule
-    public MultiThreadedMultiInvoker i = new MultiThreadedMultiInvoker( MultiThreadedMultiInvoker.NOT_THREADSAFE );
-    private static final String BASE = "ou=system";
-    private static final String RDN_TORI_AMOS = "cn=Tori Amos";
-    private static final String PERSON_DESCRIPTION = "an American singer-songwriter";
-    private static final String RDN_DEBBIE_HARRY = "cn=Debbie Harry";
-    
-    
-    /**
-     * Creation of required attributes of a person entry.
-     */
-    protected Attributes getPersonAttributes( String sn, String cn ) throws LdapException
-    {
-        Attributes attributes = LdifUtils.createJndiAttributes(
-            "objectClass: top",
-            "objectClass: person",
-            "objectClass: organizationalperson",
-            "objectClass: inetorgperson",
-            "cn", cn,
-            "sn", sn );
-    
-        return attributes;
-    }
-    
-    
-    /**
-     * Add a new attribute to a person entry.
-     */
-    @Test
-    public void testAddNewAttributeValue() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        // Add telephoneNumber attribute
-        String newValue = "1234567890";
-        Attributes attrs = new BasicAttributes( "telephoneNumber", newValue, true );
+@Rule
+public MultiThreadedMultiInvoker i = new MultiThreadedMultiInvoker( MultiThreadedMultiInvoker.NOT_THREADSAFE );
+private static final String BASE = "ou=system";
+private static final String RDN_TORI_AMOS = "cn=Tori Amos";
+private static final String PERSON_DESCRIPTION = "an American singer-songwriter";
+private static final String RDN_DEBBIE_HARRY = "cn=Debbie Harry";
+
+
+/**
+ * Creation of required attributes of a person entry.
+ */
+protected Attributes getPersonAttributes( String sn, String cn ) throws LdapException
+{
+    Attributes attributes = LdifUtils.createJndiAttributes(
+        "objectClass: top",
+        "objectClass: person",
+        "objectClass: organizationalperson",
+        "objectClass: inetorgperson",
+        "cn", cn,
+        "sn", sn );
+
+    return attributes;
+}
+
+
+/**
+ * Add a new attribute to a person entry.
+ */
+@Test
+public void testAddNewAttributeValue() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    // Add telephoneNumber attribute
+    String newValue = "1234567890";
+    Attributes attrs = new BasicAttributes( "telephoneNumber", newValue, true );
+    ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
+
+    // Verify, that
+    // - case of attribute description is correct
+    // - attribute value is added
+    attrs = ctx.getAttributes( RDN_TORI_AMOS );
+    Attribute attr = attrs.get( "telephoneNumber" );
+    assertNotNull( attr );
+    assertEquals( "telephoneNumber", attr.getID() );
+    assertTrue( attr.contains( newValue ) );
+    assertEquals( 1, attr.size() );
+}
+
+
+/**
+ * Add a new attribute with two values.
+ */
+@Test
+public void testAddNewAttributeValues() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    // Add telephoneNumber attribute
+    String[] newValues =
+        { "1234567890", "999999999" };
+    Attribute attr = new BasicAttribute( "telephoneNumber" );
+    attr.add( newValues[0] );
+    attr.add( newValues[1] );
+    Attributes attrs = new BasicAttributes( true );
+    attrs.put( attr );
+    ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
+
+    // Verify, that
+    // - case of attribute description is correct
+    // - attribute values are present
+    attrs = ctx.getAttributes( RDN_TORI_AMOS );
+    attr = attrs.get( "telephoneNumber" );
+    assertNotNull( attr );
+    assertEquals( "telephoneNumber", attr.getID() );
+    assertTrue( attr.contains( newValues[0] ) );
+    assertTrue( attr.contains( newValues[1] ) );
+    assertEquals( newValues.length, attr.size() );
+}
+
+
+/**
+ * Add an additional value.
+ */
+@Test
+public void testAddAdditionalAttributeValue() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    // A new description attribute value
+    String newValue = "A new description for this person";
+    assertFalse( newValue.equals( PERSON_DESCRIPTION ) );
+    Attributes attrs = new BasicAttributes( "description", newValue, true );
+
+    ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
+
+    // Verify, that attribute value is added
+    attrs = ctx.getAttributes( RDN_TORI_AMOS );
+    Attribute attr = attrs.get( "description" );
+    assertNotNull( attr );
+    assertTrue( attr.contains( newValue ) );
+    assertTrue( attr.contains( PERSON_DESCRIPTION ) );
+    assertEquals( 2, attr.size() );
+}
+
+
+/**
+ * Try to add an already existing attribute value.
+ *
+ * Expected behaviour: Modify operation fails with an
+ * AttributeInUseException. Original LDAP Error code: 20 (Indicates that the
+ * attribute value specified in a modify or add operation already exists as
+ * a value for that attribute).
+ */
+@Test
+public void testAddExistingAttributeValue() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    // Change description attribute
+    Attributes attrs = new BasicAttributes( "description", PERSON_DESCRIPTION, true );
+
+    try
+    {
         ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
-    
-        // Verify, that
-        // - case of attribute description is correct
-        // - attribute value is added
-        attrs = ctx.getAttributes( RDN_TORI_AMOS );
-        Attribute attr = attrs.get( "telephoneNumber" );
-        assertNotNull( attr );
-        assertEquals( "telephoneNumber", attr.getID() );
-        assertTrue( attr.contains( newValue ) );
-        assertEquals( 1, attr.size() );
+        fail( "Adding an already existing atribute value should fail." );
     }
-    
-    
-    /**
-     * Add a new attribute with two values.
-     */
-    @Test
-    public void testAddNewAttributeValues() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        // Add telephoneNumber attribute
-        String[] newValues =
-            { "1234567890", "999999999" };
-        Attribute attr = new BasicAttribute( "telephoneNumber" );
-        attr.add( newValues[0] );
-        attr.add( newValues[1] );
-        Attributes attrs = new BasicAttributes( true );
-        attrs.put( attr );
-        ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
-    
-        // Verify, that
-        // - case of attribute description is correct
-        // - attribute values are present
-        attrs = ctx.getAttributes( RDN_TORI_AMOS );
-        attr = attrs.get( "telephoneNumber" );
-        assertNotNull( attr );
-        assertEquals( "telephoneNumber", attr.getID() );
-        assertTrue( attr.contains( newValues[0] ) );
-        assertTrue( attr.contains( newValues[1] ) );
-        assertEquals( newValues.length, attr.size() );
-    }
-    
-    
-    /**
-     * Add an additional value.
-     */
-    @Test
-    public void testAddAdditionalAttributeValue() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        // A new description attribute value
-        String newValue = "A new description for this person";
-        assertFalse( newValue.equals( PERSON_DESCRIPTION ) );
-        Attributes attrs = new BasicAttributes( "description", newValue, true );
-    
+    catch ( AttributeInUseException e )
+    {
+        // expected behaviour
+    }
+
+    // Verify, that attribute is still there, and is the only one
+    attrs = ctx.getAttributes( RDN_TORI_AMOS );
+    Attribute attr = attrs.get( "description" );
+    assertNotNull( attr );
+    assertTrue( attr.contains( PERSON_DESCRIPTION ) );
+    assertEquals( 1, attr.size() );
+}
+
+
+/**
+ * Try to add an already existing attribute value.
+ *
+ * Expected behaviour: Modify operation fails with an
+ * AttributeInUseException. Original LDAP Error code: 20 (Indicates that the
+ * attribute value specified in a modify or add operation already exists as
+ * a value for that attribute).
+ *
+ * Check for bug DIR_SERVER664
+ */
+@Test
+public void testAddExistingNthAttributesDirServer664() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    // Change description attribute
+    Attributes attrs = new BasicAttributes( true );
+    attrs.put( new BasicAttribute( "telephoneNumber", "1" ) );
+    attrs.put( new BasicAttribute( "telephoneNumber", "2" ) );
+    attrs.put( new BasicAttribute( "telephoneNumber", "3" ) );
+    attrs.put( new BasicAttribute( "telephoneNumber", "4" ) );
+    attrs.put( new BasicAttribute( "telephoneNumber", "5" ) );
+    attrs.put( new BasicAttribute( "telephoneNumber", "6" ) );
+    attrs.put( new BasicAttribute( "telephoneNumber", "7" ) );
+    attrs.put( new BasicAttribute( "telephoneNumber", "8" ) );
+    attrs.put( new BasicAttribute( "telephoneNumber", "9" ) );
+    attrs.put( new BasicAttribute( "telephoneNumber", "10" ) );
+    attrs.put( new BasicAttribute( "telephoneNumber", "11" ) );
+    attrs.put( new BasicAttribute( "telephoneNumber", "12" ) );
+    attrs.put( new BasicAttribute( "telephoneNumber", "13" ) );
+    attrs.put( new BasicAttribute( "telephoneNumber", "14" ) );
+
+    Attribute attr = new BasicAttribute( "description", PERSON_DESCRIPTION );
+
+    attrs.put( attr );
+
+    try
+    {
         ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
-    
-        // Verify, that attribute value is added
-        attrs = ctx.getAttributes( RDN_TORI_AMOS );
-        Attribute attr = attrs.get( "description" );
-        assertNotNull( attr );
-        assertTrue( attr.contains( newValue ) );
-        assertTrue( attr.contains( PERSON_DESCRIPTION ) );
-        assertEquals( 2, attr.size() );
+        fail( "Adding an already existing atribute value should fail." );
     }
-    
-    
-    /**
-     * Try to add an already existing attribute value.
-     *
-     * Expected behaviour: Modify operation fails with an
-     * AttributeInUseException. Original LDAP Error code: 20 (Indicates that the
-     * attribute value specified in a modify or add operation already exists as
-     * a value for that attribute).
-     */
-    @Test
-    public void testAddExistingAttributeValue() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        // Change description attribute
-        Attributes attrs = new BasicAttributes( "description", PERSON_DESCRIPTION, true );
-    
-        try
-        {
-            ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
-            fail( "Adding an already existing atribute value should fail." );
-        }
-        catch ( AttributeInUseException e )
-        {
-            // expected behaviour
-        }
-    
-        // Verify, that attribute is still there, and is the only one
-        attrs = ctx.getAttributes( RDN_TORI_AMOS );
-        Attribute attr = attrs.get( "description" );
-        assertNotNull( attr );
-        assertTrue( attr.contains( PERSON_DESCRIPTION ) );
-        assertEquals( 1, attr.size() );
+    catch ( AttributeInUseException e )
+    {
+        // expected behaviour
     }
-    
-    
-    /**
-     * Try to add an already existing attribute value.
-     *
-     * Expected behaviour: Modify operation fails with an
-     * AttributeInUseException. Original LDAP Error code: 20 (Indicates that the
-     * attribute value specified in a modify or add operation already exists as
-     * a value for that attribute).
-     *
-     * Check for bug DIR_SERVER664
-     */
-    @Test
-    public void testAddExistingNthAttributesDirServer664() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        // Change description attribute
-        Attributes attrs = new BasicAttributes( true );
-        attrs.put( new BasicAttribute( "telephoneNumber", "1" ) );
-        attrs.put( new BasicAttribute( "telephoneNumber", "2" ) );
-        attrs.put( new BasicAttribute( "telephoneNumber", "3" ) );
-        attrs.put( new BasicAttribute( "telephoneNumber", "4" ) );
-        attrs.put( new BasicAttribute( "telephoneNumber", "5" ) );
-        attrs.put( new BasicAttribute( "telephoneNumber", "6" ) );
-        attrs.put( new BasicAttribute( "telephoneNumber", "7" ) );
-        attrs.put( new BasicAttribute( "telephoneNumber", "8" ) );
-        attrs.put( new BasicAttribute( "telephoneNumber", "9" ) );
-        attrs.put( new BasicAttribute( "telephoneNumber", "10" ) );
-        attrs.put( new BasicAttribute( "telephoneNumber", "11" ) );
-        attrs.put( new BasicAttribute( "telephoneNumber", "12" ) );
-        attrs.put( new BasicAttribute( "telephoneNumber", "13" ) );
-        attrs.put( new BasicAttribute( "telephoneNumber", "14" ) );
-    
-        Attribute attr = new BasicAttribute( "description", PERSON_DESCRIPTION );
-    
-        attrs.put( attr );
-    
-        try
-        {
-            ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
-            fail( "Adding an already existing atribute value should fail." );
-        }
-        catch ( AttributeInUseException e )
-        {
-            // expected behaviour
-        }
-    
-        // Verify, that attribute is still there, and is the only one
-        attrs = ctx.getAttributes( RDN_TORI_AMOS );
-        attr = attrs.get( "description" );
-        assertNotNull( attr );
-        assertTrue( attr.contains( PERSON_DESCRIPTION ) );
-        assertEquals( 1, attr.size() );
+
+    // Verify, that attribute is still there, and is the only one
+    attrs = ctx.getAttributes( RDN_TORI_AMOS );
+    attr = attrs.get( "description" );
+    assertNotNull( attr );
+    assertTrue( attr.contains( PERSON_DESCRIPTION ) );
+    assertEquals( 1, attr.size() );
+}
+
+
+/**
+ * Check for DIR_SERVER_643
+ */
+@Test
+public void testTwoDescriptionDirServer643() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    // Change description attribute
+    Attributes attrs = new BasicAttributes( true );
+    Attribute attr = new BasicAttribute( "description",
+        "a British singer-songwriter with an expressive four-octave voice" );
+    attr.add( "one of the most influential female artists of the twentieth century" );
+    attrs.put( attr );
+
+    ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
+
+    // Verify, that attribute is still there, and is the only one
+    attrs = ctx.getAttributes( RDN_TORI_AMOS );
+    attr = attrs.get( "description" );
+    assertNotNull( attr );
+    assertEquals( 3, attr.size() );
+    assertTrue( attr.contains( "a British singer-songwriter with an expressive four-octave voice" ) );
+    assertTrue( attr.contains( "one of the most influential female artists of the twentieth century" ) );
+    assertTrue( attr.contains( PERSON_DESCRIPTION ) );
+}
+
+
+/**
+ * Try to add a duplicate attribute value to an entry, where this attribute
+ * is already present (objectclass in this case). Expected behaviour is that
+ * the modify operation causes an error (error code 20, "Attribute or value
+ * exists").
+ */
+@Test
+public void testAddDuplicateValueToExistingAttribute() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    // modify object classes, add a new value twice
+    Attribute ocls = new BasicAttribute( "objectClass", "organizationalPerson" );
+    ModificationItem[] modItems = new ModificationItem[2];
+    modItems[0] = new ModificationItem( DirContext.ADD_ATTRIBUTE, ocls );
+    modItems[1] = new ModificationItem( DirContext.ADD_ATTRIBUTE, ocls );
+    try
+    {
+        ctx.modifyAttributes( RDN_TORI_AMOS, modItems );
+        fail( "Adding a duplicate attribute value should cause an error." );
+    }
+    catch ( AttributeInUseException ex )
+    {
     }
-    
-    
-    /**
-     * Check for DIR_SERVER_643
-     */
-    @Test
-    public void testTwoDescriptionDirServer643() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        // Change description attribute
-        Attributes attrs = new BasicAttributes( true );
-        Attribute attr = new BasicAttribute( "description",
-            "a British singer-songwriter with an expressive four-octave voice" );
-        attr.add( "one of the most influential female artists of the twentieth century" );
-        attrs.put( attr );
-    
+
+    // Check, whether attribute objectClass is unchanged
+    Attributes attrs = ctx.getAttributes( RDN_TORI_AMOS );
+    ocls = attrs.get( "objectClass" );
+    assertEquals( ocls.size(), 4 );
+    assertTrue( ocls.contains( "top" ) );
+    assertTrue( ocls.contains( "person" ) );
+}
+
+
+/**
+ * Try to add a duplicate attribute value to an entry, where this attribute
+ * is not present. Expected behaviour is that the modify operation causes an
+ * error (error code 20, "Attribute or value exists").
+ */
+@Test
+public void testAddDuplicateValueToNewAttribute() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    // add the same description value twice
+    Attribute desc = new BasicAttribute( "description", "another description value besides songwriter" );
+    ModificationItem[] modItems = new ModificationItem[2];
+    modItems[0] = new ModificationItem( DirContext.ADD_ATTRIBUTE, desc );
+    modItems[1] = new ModificationItem( DirContext.ADD_ATTRIBUTE, desc );
+    try
+    {
+        ctx.modifyAttributes( RDN_TORI_AMOS, modItems );
+        fail( "Adding a duplicate attribute value should cause an error." );
+    }
+    catch ( AttributeInUseException ex )
+    {
+    }
+
+    // Check, whether attribute description is still not present
+    Attributes attrs = ctx.getAttributes( RDN_TORI_AMOS );
+    assertEquals( 1, attrs.get( "description" ).size() );
+}
+
+
+/**
+ * Modify the entry with a bad attribute : this should fail
+ */
+@Test
+public void testSearchBadAttribute() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    // Add a not existing attribute
+    String newValue = "unbelievable";
+    Attributes attrs = new BasicAttributes( "voice", newValue, true );
+
+    try
+    {
         ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
-    
-        // Verify, that attribute is still there, and is the only one
-        attrs = ctx.getAttributes( RDN_TORI_AMOS );
-        attr = attrs.get( "description" );
-        assertNotNull( attr );
-        assertEquals( 3, attr.size() );
-        assertTrue( attr.contains( "a British singer-songwriter with an expressive four-octave voice" ) );
-        assertTrue( attr.contains( "one of the most influential female artists of the twentieth century" ) );
-        assertTrue( attr.contains( PERSON_DESCRIPTION ) );
-    }
-    
-    
-    /**
-     * Try to add a duplicate attribute value to an entry, where this attribute
-     * is already present (objectclass in this case). Expected behaviour is that
-     * the modify operation causes an error (error code 20, "Attribute or value
-     * exists").
-     */
-    @Test
-    public void testAddDuplicateValueToExistingAttribute() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        // modify object classes, add a new value twice
-        Attribute ocls = new BasicAttribute( "objectClass", "organizationalPerson" );
-        ModificationItem[] modItems = new ModificationItem[2];
-        modItems[0] = new ModificationItem( DirContext.ADD_ATTRIBUTE, ocls );
-        modItems[1] = new ModificationItem( DirContext.ADD_ATTRIBUTE, ocls );
-        try
-        {
-            ctx.modifyAttributes( RDN_TORI_AMOS, modItems );
-            fail( "Adding a duplicate attribute value should cause an error." );
-        }
-        catch ( AttributeInUseException ex )
-        {
-        }
-    
-        // Check, whether attribute objectClass is unchanged
-        Attributes attrs = ctx.getAttributes( RDN_TORI_AMOS );
-        ocls = attrs.get( "objectClass" );
-        assertEquals( ocls.size(), 4 );
-        assertTrue( ocls.contains( "top" ) );
-        assertTrue( ocls.contains( "person" ) );
-    }
-    
-    
-    /**
-     * Try to add a duplicate attribute value to an entry, where this attribute
-     * is not present. Expected behaviour is that the modify operation causes an
-     * error (error code 20, "Attribute or value exists").
-     */
-    @Test
-    public void testAddDuplicateValueToNewAttribute() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        // add the same description value twice
-        Attribute desc = new BasicAttribute( "description", "another description value besides songwriter" );
-        ModificationItem[] modItems = new ModificationItem[2];
-        modItems[0] = new ModificationItem( DirContext.ADD_ATTRIBUTE, desc );
-        modItems[1] = new ModificationItem( DirContext.ADD_ATTRIBUTE, desc );
-        try
-        {
-            ctx.modifyAttributes( RDN_TORI_AMOS, modItems );
-            fail( "Adding a duplicate attribute value should cause an error." );
-        }
-        catch ( AttributeInUseException ex )
-        {
-        }
-    
-        // Check, whether attribute description is still not present
-        Attributes attrs = ctx.getAttributes( RDN_TORI_AMOS );
-        assertEquals( 1, attrs.get( "description" ).size() );
-    }
-    
-    
-    /**
-     * Modify the entry with a bad attribute : this should fail
-     */
-    @Test
-    public void testSearchBadAttribute() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        // Add a not existing attribute
-        String newValue = "unbelievable";
-        Attributes attrs = new BasicAttributes( "voice", newValue, true );
-    
-        try
-        {
-            ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
-        }
-        catch ( NoSuchAttributeException nsae )
+    }
+    catch ( NoSuchAttributeException nsae )
+    {
+        // We have a failure : the attribute is unknown in the schema
+        assertTrue( true );
+        return;
+    }
+
+    fail( "Cannot reach this point" );
+}
+
+
+/**
+ * Create a person entry and perform a modify op, in which
+ * we modify an attribute two times.
+ */
+@Test
+public void testAttributeValueMultiMofificationDIRSERVER_636() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    // Create a person entry
+    Attributes attrs = getPersonAttributes( "Bush", "Kate Bush" );
+    String rdn = "cn=Kate Bush";
+    ctx.createSubcontext( rdn, attrs );
+
+    // Add a description with two values
+    String[] descriptions =
         {
-            // We have a failure : the attribute is unknown in the schema
-            assertTrue( true );
-            return;
-        }
-    
-        fail( "Cannot reach this point" );
-    }
-    
-    
-    /**
-     * Create a person entry and perform a modify op, in which
-     * we modify an attribute two times.
-     */
-    @Test
-    public void testAttributeValueMultiMofificationDIRSERVER_636() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        // Create a person entry
-        Attributes attrs = getPersonAttributes( "Bush", "Kate Bush" );
-        String rdn = "cn=Kate Bush";
-        ctx.createSubcontext( rdn, attrs );
-    
-        // Add a description with two values
-        String[] descriptions =
-            {
-                "Kate Bush is a British singer-songwriter.",
-                "She has become one of the most influential female artists of the twentieth century." };
-        Attribute desc1 = new BasicAttribute( "description" );
-        desc1.add( descriptions[0] );
-        desc1.add( descriptions[1] );
-    
-        ModificationItem addModOp = new ModificationItem(
-            DirContext.ADD_ATTRIBUTE, desc1 );
-    
-        Attribute desc2 = new BasicAttribute( "description" );
-        desc2.add( descriptions[1] );
-        ModificationItem delModOp = new ModificationItem(
-            DirContext.REMOVE_ATTRIBUTE, desc2 );
-    
+            "Kate Bush is a British singer-songwriter.",
+            "She has become one of the most influential female artists of the twentieth century." };
+    Attribute desc1 = new BasicAttribute( "description" );
+    desc1.add( descriptions[0] );
+    desc1.add( descriptions[1] );
+
+    ModificationItem addModOp = new ModificationItem(
+        DirContext.ADD_ATTRIBUTE, desc1 );
+
+    Attribute desc2 = new BasicAttribute( "description" );
+    desc2.add( descriptions[1] );
+    ModificationItem delModOp = new ModificationItem(
+        DirContext.REMOVE_ATTRIBUTE, desc2 );
+
+    ctx.modifyAttributes( rdn, new ModificationItem[]
+        { addModOp,
+            delModOp } );
+
+    SearchControls sctls = new SearchControls();
+    sctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
+    String filter = "(cn=*Bush)";
+    String base = "";
+
+    // Check entry
+    NamingEnumeration<SearchResult> enm = ctx.search( base, filter, sctls );
+    assertTrue( enm.hasMore() );
+
+    while ( enm.hasMore() )
+    {
+        SearchResult sr = enm.next();
+        attrs = sr.getAttributes();
+        Attribute desc = sr.getAttributes().get( "description" );
+        assertEquals( 1, desc.size() );
+        assertTrue( desc.contains( descriptions[0] ) );
+    }
+
+    // Remove the person entry
+    ctx.destroySubcontext( rdn );
+}
+
+
+/**
+ * Try to add subschemaSubentry attribute to an entry
+ */
+@Test
+public void testModifyOperationalAttributeAdd() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    ModificationItem modifyOp = new ModificationItem( DirContext.ADD_ATTRIBUTE, new BasicAttribute(
+        "subschemaSubentry", "cn=anotherSchema" ) );
+
+    try
+    {
+        ctx.modifyAttributes( RDN_DEBBIE_HARRY, new ModificationItem[]
+            { modifyOp } );
+
+        fail( "modification of entry should fail" );
+    }
+    catch ( InvalidAttributeValueException e )
+    {
+        // Expected result
+    }
+    catch ( NoPermissionException e )
+    {
+        // Expected result
+    }
+}
+
+
+/**
+ * Create a person entry and perform a modify op on an
+ * attribute which is part of the Dn. This is not allowed.
+ *
+ * A JIRA has been created for this bug : DIRSERVER_687
+ */
+@Test
+public void testDNAttributeMemberModificationDIRSERVER_687() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    // Create a person entry
+    Attributes attrs = getPersonAttributes( "Bush", "Kate Bush" );
+    String rdn = "cn=Kate Bush";
+    ctx.createSubcontext( rdn, attrs );
+
+    // Try to modify the cn attribute
+    Attribute desc1 = new BasicAttribute( "cn", "Georges Bush" );
+
+    ModificationItem addModOp = new ModificationItem(
+        DirContext.REPLACE_ATTRIBUTE, desc1 );
+
+    try
+    {
         ctx.modifyAttributes( rdn, new ModificationItem[]
-            { addModOp,
-                delModOp } );
-    
-        SearchControls sctls = new SearchControls();
-        sctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
-        String filter = "(cn=*Bush)";
-        String base = "";
-    
-        // Check entry
-        NamingEnumeration<SearchResult> enm = ctx.search( base, filter, sctls );
-        assertTrue( enm.hasMore() );
-    
-        while ( enm.hasMore() )
-        {
-            SearchResult sr = enm.next();
-            attrs = sr.getAttributes();
-            Attribute desc = sr.getAttributes().get( "description" );
-            assertEquals( 1, desc.size() );
-            assertTrue( desc.contains( descriptions[0] ) );
-        }
-    
+            { addModOp } );
+        fail();
+    }
+    catch ( AttributeModificationException ame )
+    {
+        assertTrue( true );
         // Remove the person entry
         ctx.destroySubcontext( rdn );
     }
-    
-    
-    /**
-     * Try to add subschemaSubentry attribute to an entry
-     */
-    @Test
-    public void testModifyOperationalAttributeAdd() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        ModificationItem modifyOp = new ModificationItem( DirContext.ADD_ATTRIBUTE, new BasicAttribute(
-            "subschemaSubentry", "cn=anotherSchema" ) );
-    
-        try
-        {
-            ctx.modifyAttributes( RDN_DEBBIE_HARRY, new ModificationItem[]
-                { modifyOp } );
-    
-            fail( "modification of entry should fail" );
-        }
-        catch ( InvalidAttributeValueException e )
-        {
-            // Expected result
-        }
-        catch ( NoPermissionException e )
-        {
-            // Expected result
-        }
+    catch ( NamingException ne )
+    {
+        assertTrue( true );
+        // Remove the person entry
+        ctx.destroySubcontext( rdn );
     }
-    
-    
-    /**
-     * Create a person entry and perform a modify op on an
-     * attribute which is part of the Dn. This is not allowed.
-     *
-     * A JIRA has been created for this bug : DIRSERVER_687
-     */
-    @Test
-    public void testDNAttributeMemberModificationDIRSERVER_687() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        // Create a person entry
-        Attributes attrs = getPersonAttributes( "Bush", "Kate Bush" );
-        String rdn = "cn=Kate Bush";
-        ctx.createSubcontext( rdn, attrs );
-    
-        // Try to modify the cn attribute
-        Attribute desc1 = new BasicAttribute( "cn", "Georges Bush" );
-    
-        ModificationItem addModOp = new ModificationItem(
-            DirContext.REPLACE_ATTRIBUTE, desc1 );
-    
-        try
-        {
-            ctx.modifyAttributes( rdn, new ModificationItem[]
-                { addModOp } );
-            fail();
-        }
-        catch ( AttributeModificationException ame )
-        {
-            assertTrue( true );
-            // Remove the person entry
-            ctx.destroySubcontext( rdn );
-        }
-        catch ( NamingException ne )
-        {
-            assertTrue( true );
-            // Remove the person entry
-            ctx.destroySubcontext( rdn );
-        }
-    }
-    
-    
-    /**
-     * Try to modify an entry adding invalid number of values for a single-valued atribute
-     *
-     * @see <a href="http://issues.apache.org/jira/browse/DIRSERVER-614">DIRSERVER-614</a>
-     */
-    @Test
-    public void testModifyAddWithInvalidNumberOfAttributeValues() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        Attributes attrs = new BasicAttributes( true );
-        Attribute ocls = new BasicAttribute( "objectClass" );
-        ocls.add( "top" );
-        ocls.add( "inetOrgPerson" );
-        attrs.put( ocls );
-        attrs.put( "cn", "Fiona Apple" );
-        attrs.put( "sn", "Apple" );
-        ctx.createSubcontext( "cn=Fiona Apple", attrs );
-    
-        // add two displayNames to an inetOrgPerson
-        attrs = new BasicAttributes( true );
-        Attribute displayName = new BasicAttribute( "displayName" );
-        displayName.add( "Fiona" );
-        displayName.add( "Fiona A." );
-        attrs.put( displayName );
-    
-        try
-        {
-            ctx.modifyAttributes( "cn=Fiona Apple", DirContext.ADD_ATTRIBUTE, attrs );
-            fail( "modification of entry should fail" );
-        }
-        catch ( InvalidAttributeValueException e )
-        {
-    
-        }
+}
+
+
+/**
+ * Try to modify an entry adding invalid number of values for a single-valued atribute
+ *
+ * @see <a href="http://issues.apache.org/jira/browse/DIRSERVER-614">DIRSERVER-614</a>
+ */
+@Test
+public void testModifyAddWithInvalidNumberOfAttributeValues() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    Attributes attrs = new BasicAttributes( true );
+    Attribute ocls = new BasicAttribute( "objectClass" );
+    ocls.add( "top" );
+    ocls.add( "inetOrgPerson" );
+    attrs.put( ocls );
+    attrs.put( "cn", "Fiona Apple" );
+    attrs.put( "sn", "Apple" );
+    ctx.createSubcontext( "cn=Fiona Apple", attrs );
+
+    // add two displayNames to an inetOrgPerson
+    attrs = new BasicAttributes( true );
+    Attribute displayName = new BasicAttribute( "displayName" );
+    displayName.add( "Fiona" );
+    displayName.add( "Fiona A." );
+    attrs.put( displayName );
+
+    try
+    {
+        ctx.modifyAttributes( "cn=Fiona Apple", DirContext.ADD_ATTRIBUTE, attrs );
+        fail( "modification of entry should fail" );
     }
-    
-    
-    /**
-     * Add a new binary attribute to a person entry.
-     */
-    @Test
-    public void testAddNewBinaryAttributeValue() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        // Add a binary attribute
-        byte[] newValue = new byte[]
-            { 0x00, 0x01, 0x02, 0x03 };
-        Attributes attrs = new BasicAttributes( "userCertificate;binary", newValue, true );
-        ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
-    
-        // Verify, that attribute value is added
-        attrs = ctx.getAttributes( RDN_TORI_AMOS );
-        Attribute attr = attrs.get( "userCertificate" );
-        assertNotNull( attr );
-        assertTrue( attr.contains( newValue ) );
-        byte[] certificate = ( byte[] ) attr.get();
-        assertTrue( Arrays.equals( newValue, certificate ) );
-        assertEquals( 1, attr.size() );
+    catch ( InvalidAttributeValueException e )
+    {
+
     }
-    
-    
-    /**
-     * Add a new attribute to a person entry.
-     */
-    @Test
-    public void testAddNewBinaryAttributeValueAbove0x80() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        // Add a binary attribute
-        byte[] newValue = new byte[]
-            { ( byte ) 0x80, ( byte ) 0x81, ( byte ) 0x82, ( byte ) 0x83 };
-        Attributes attrs = new BasicAttributes( "userCertificate;binary", newValue, true );
-        ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
-    
-        // Verify, that attribute value is added
-        attrs = ctx.getAttributes( RDN_TORI_AMOS );
+}
+
+
+/**
+ * Add a new binary attribute to a person entry.
+ */
+@Test
+public void testAddNewBinaryAttributeValue() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    // Add a binary attribute
+    byte[] newValue = new byte[]
+        { 0x00, 0x01, 0x02, 0x03 };
+    Attributes attrs = new BasicAttributes( "userCertificate;binary", newValue, true );
+    ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
+
+    // Verify, that attribute value is added
+    attrs = ctx.getAttributes( RDN_TORI_AMOS );
+    Attribute attr = attrs.get( "userCertificate" );
+    assertNotNull( attr );
+    assertTrue( attr.contains( newValue ) );
+    byte[] certificate = ( byte[] ) attr.get();
+    assertTrue( Arrays.equals( newValue, certificate ) );
+    assertEquals( 1, attr.size() );
+}
+
+
+/**
+ * Add a new attribute to a person entry.
+ */
+@Test
+public void testAddNewBinaryAttributeValueAbove0x80() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    // Add a binary attribute
+    byte[] newValue = new byte[]
+        { ( byte ) 0x80, ( byte ) 0x81, ( byte ) 0x82, ( byte ) 0x83 };
+    Attributes attrs = new BasicAttributes( "userCertificate;binary", newValue, true );
+    ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
+
+    // Verify, that attribute value is added
+    attrs = ctx.getAttributes( RDN_TORI_AMOS );
+    Attribute attr = attrs.get( "userCertificate" );
+    assertNotNull( attr );
+    assertTrue( attr.contains( newValue ) );
+    byte[] certificate = ( byte[] ) attr.get();
+    assertTrue( Arrays.equals( newValue, certificate ) );
+    assertEquals( 1, attr.size() );
+}
+
+
+/**
+ * Add a new binary attribute to a person entry.
+ */
+@Test
+public void testRetrieveEntryWithBinaryAttributeValue() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    // Add a ;binary attribute
+    byte[] newValue = new byte[]
+        { 0x00, 0x01, 0x02, 0x03 };
+    Attributes attrs = new BasicAttributes( "userCertificate;binary", newValue );
+    ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
+
+    // Search entry an request ;binary attribute
+    SearchControls sctls = new SearchControls();
+    sctls.setSearchScope( SearchControls.OBJECT_SCOPE );
+    sctls.setReturningAttributes( new String[]
+        { "userCertificate;binary" } );
+    String filter = "(objectClass=*)";
+    String base = RDN_TORI_AMOS;
+
+    // Test that ;binary attribute is present
+    NamingEnumeration<SearchResult> enm = ctx.search( base, filter, sctls );
+    assertTrue( enm.hasMore() );
+
+    while ( enm.hasMore() )
+    {
+        SearchResult sr = enm.next();
+        attrs = sr.getAttributes();
         Attribute attr = attrs.get( "userCertificate" );
         assertNotNull( attr );
         assertTrue( attr.contains( newValue ) );
@@ -625,73 +674,113 @@ public class ModifyAddIT extends Abstrac
         assertTrue( Arrays.equals( newValue, certificate ) );
         assertEquals( 1, attr.size() );
     }
-    
-    
-    /**
-     * Add a new binary attribute to a person entry.
-     */
-    @Test
-    public void testRetrieveEntryWithBinaryAttributeValue() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        // Add a ;binary attribute
-        byte[] newValue = new byte[]
-            { 0x00, 0x01, 0x02, 0x03 };
-        Attributes attrs = new BasicAttributes( "userCertificate;binary", newValue );
-        ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
-    
-        // Search entry an request ;binary attribute
-        SearchControls sctls = new SearchControls();
-        sctls.setSearchScope( SearchControls.OBJECT_SCOPE );
-        sctls.setReturningAttributes( new String[]
-            { "userCertificate;binary" } );
-        String filter = "(objectClass=*)";
-        String base = RDN_TORI_AMOS;
-    
-        // Test that ;binary attribute is present
-        NamingEnumeration<SearchResult> enm = ctx.search( base, filter, sctls );
-        assertTrue( enm.hasMore() );
-    
-        while ( enm.hasMore() )
-        {
-            SearchResult sr = enm.next();
-            attrs = sr.getAttributes();
-            Attribute attr = attrs.get( "userCertificate" );
-            assertNotNull( attr );
-            assertTrue( attr.contains( newValue ) );
-            byte[] certificate = ( byte[] ) attr.get();
-            assertTrue( Arrays.equals( newValue, certificate ) );
-            assertEquals( 1, attr.size() );
-        }
-    
-    }
-    
-    
-    /**
-     * Add a new ;binary attribute with bytes greater than 0x80
-     * to a person entry.
-     * Test for DIRSERVER-1146
-     *
-     * @throws NamingException
-     */
-    public void testAddNewBinaryAttributeValue0x80() throws Exception
-    {
-        DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
-    
-        // Add a ;binary attribute with high-bytes
-        byte[] newValue = new byte[]
-            { ( byte ) 0x80, ( byte ) 0x81, ( byte ) 0x82, ( byte ) 0x83 };
-        Attributes attrs = new BasicAttributes( "userCertificate;binary", newValue );
-        ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
-    
-        // Verify, that attribute value is added
-        attrs = ctx.getAttributes( RDN_TORI_AMOS );
-        Attribute attr = attrs.get( "userCertificate" );
-        assertNotNull( attr );
-        assertTrue( attr.contains( newValue ) );
-        byte[] certificate = ( byte[] ) attr.get();
-        assertTrue( Arrays.equals( newValue, certificate ) );
-        assertEquals( 1, attr.size() );
+
+}
+
+
+/**
+ * Add a new ;binary attribute with bytes greater than 0x80
+ * to a person entry.
+ * Test for DIRSERVER-1146
+ *
+ * @throws NamingException
+ */
+public void testAddNewBinaryAttributeValue0x80() throws Exception
+{
+    DirContext ctx = ( DirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+
+    // Add a ;binary attribute with high-bytes
+    byte[] newValue = new byte[]
+        { ( byte ) 0x80, ( byte ) 0x81, ( byte ) 0x82, ( byte ) 0x83 };
+    Attributes attrs = new BasicAttributes( "userCertificate;binary", newValue );
+    ctx.modifyAttributes( RDN_TORI_AMOS, DirContext.ADD_ATTRIBUTE, attrs );
+
+    // Verify, that attribute value is added
+    attrs = ctx.getAttributes( RDN_TORI_AMOS );
+    Attribute attr = attrs.get( "userCertificate" );
+    assertNotNull( attr );
+    assertTrue( attr.contains( newValue ) );
+    byte[] certificate = ( byte[] ) attr.get();
+    assertTrue( Arrays.equals( newValue, certificate ) );
+    assertEquals( 1, attr.size() );
+}
+
+
+@Test
+public void testModifyMultipleValues() throws LdapException, IOException
+{
+    LdapConnection connection = new LdapNetworkConnection( "localhost", getLdapServer().getPort() );
+    connection.setTimeOut( 0L );
+
+    // Use the client API
+    connection.bind( "uid=admin,ou=system", "secret" );
+
+    // Add a new entry with some null values
+    Entry entry = new DefaultEntry( "uid=12345,ou=system",
+        "ObjectClass: top",
+        "ObjectClass: person",
+        "ObjectClass: person",
+        "ObjectClass: OrganizationalPerson",
+        "ObjectClass: inetOrgPerson",
+        "uid: 12345",
+        "cn: test",
+        "sn: Test",
+        "userPassword: null" );
+
+    connection.add( entry );
+
+    // Now modify the entry
+    connection.modify( new Dn( "uid=12345,ou=system" ),
+        new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, "sn", "foo" ),
+        new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, "cn", "Foo" ),
+        new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, "userPassword", "123456" ),
+        new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, "givenname", "foo" ),
+        new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, "displayName", "foo" ),
+        new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, "employeeNumber", "foo" ),
+        new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, "mail" )
+        );
+
+    // Get back the entry
+    Entry found = connection.lookup( "uid=12345,ou=system" );
+
+    assertNotNull( found );
+    assertNotNull( found.get( "userPassword" ) );
+    assertTrue( found.contains( "mail", Strings.EMPTY_BYTES ) );
+
+    connection.close();
+}
+
+
+@Test
+public void testAddNullValueDirectoryString() throws LdapException, IOException
+{
+    LdapConnection connection = new LdapNetworkConnection( "localhost", getLdapServer().getPort() );
+    connection.setTimeOut( 0L );
+
+    // Use the client API
+    connection.bind( "uid=admin,ou=system", "secret" );
+
+    // Add a new entry with some null values
+    Entry entry = new DefaultEntry( "cn=test,ou=system",
+        "ObjectClass: top",
+        "ObjectClass: person",
+        "ObjectClass: person",
+        "ObjectClass: OrganizationalPerson",
+        "ObjectClass: inetOrgPerson",
+        "cn: test",
+        "sn: Test",
+        "displayName:" ); // The DisplayName must contain a value
+
+    try
+    {
+        connection.add( entry );
+        fail();
     }
+    catch ( LdapInvalidAttributeValueException liave )
+    {
+        // Expected
+    }
+
+    connection.close();
+}
 }

Modified: directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/AbstractBTreePartition.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/AbstractBTreePartition.java?rev=1496979&r1=1496978&r2=1496979&view=diff
==============================================================================
--- directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/AbstractBTreePartition.java (original)
+++ directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/AbstractBTreePartition.java Wed Jun 26 15:56:46 2013
@@ -36,8 +36,10 @@ import java.util.concurrent.locks.Reentr
 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
 import org.apache.directory.api.ldap.model.cursor.Cursor;
 import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.BinaryValue;
 import org.apache.directory.api.ldap.model.entry.Entry;
 import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.StringValue;
 import org.apache.directory.api.ldap.model.entry.Value;
 import org.apache.directory.api.ldap.model.exception.LdapAliasDereferencingException;
 import org.apache.directory.api.ldap.model.exception.LdapAliasException;
@@ -1257,9 +1259,17 @@ public abstract class AbstractBTreeParti
         {
             Index<?, Entry, String> index = getUserIndex( attributeType );
 
-            for ( Value<?> value : mods )
+            if ( mods.size() > 0 )
+            {
+                for ( Value<?> value : mods )
+                {
+                    ( ( Index ) index ).add( value.getNormValue(), id );
+                }
+            }
+            else
             {
-                ( ( Index ) index ).add( value.getNormValue(), id );
+                // Special case when we have null values
+                ( ( Index ) index ).add( null, id );
             }
 
             // If the attr didn't exist for this id add it to presence index
@@ -1285,9 +1295,24 @@ public abstract class AbstractBTreeParti
         }
 
         // add all the values in mods to the same attribute in the entry
-        for ( Value<?> value : mods )
+        if ( mods.size() > 0 )
         {
-            entry.add( mods.getAttributeType(), value );
+            for ( Value<?> value : mods )
+            {
+                entry.add( mods.getAttributeType(), value );
+            }
+        }
+        else
+        {
+            // Special cases for null values
+            if ( mods.getAttributeType().getSyntax().isHumanReadable() )
+            {
+                entry.add( mods.getAttributeType(), new StringValue( null ) );
+            }
+            else
+            {
+                entry.add( mods.getAttributeType(), new BinaryValue( null ) );
+            }
         }
 
         if ( modsOid.equals( SchemaConstants.ALIASED_OBJECT_NAME_AT_OID ) )