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 2008/03/31 18:20:08 UTC

svn commit: r643046 [2/8] - in /directory: apacheds/branches/bigbang/benchmarks/ apacheds/branches/bigbang/core-constants/src/main/java/org/apache/directory/server/constants/ apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/serve...

Modified: directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerEntry.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerEntry.java?rev=643046&r1=643045&r2=643046&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerEntry.java (original)
+++ directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerEntry.java Mon Mar 31 09:19:45 2008
@@ -24,20 +24,21 @@
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
 import org.apache.directory.server.schema.registries.Registries;
 import org.apache.directory.shared.ldap.NotImplementedException;
 import org.apache.directory.shared.ldap.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.entry.AbstractEntry;
+import org.apache.directory.shared.ldap.entry.Entry;
+import org.apache.directory.shared.ldap.entry.EntryAttribute;
 import org.apache.directory.shared.ldap.entry.Value;
 import org.apache.directory.shared.ldap.name.LdapDN;
 import org.apache.directory.shared.ldap.schema.AttributeType;
-import org.apache.directory.shared.ldap.schema.ObjectClass;
 import org.apache.directory.shared.ldap.util.StringTools;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -55,7 +56,7 @@
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  * @version $Rev$, $Date$
  */
-public final class DefaultServerEntry implements ServerEntry, Externalizable
+public final class DefaultServerEntry extends AbstractEntry<AttributeType> implements ServerEntry, Externalizable
 {
     /** Used for serialization */
     public static final long serialVersionUID = 2L;
@@ -63,22 +64,65 @@
     /** The logger for this class */
     private static final Logger LOG = LoggerFactory.getLogger( DefaultServerEntry.class );
 
-    /** A map containing all the attributes for this entry */
-    private Map<AttributeType, ServerAttribute> serverAttributeMap = new HashMap<AttributeType, ServerAttribute>();
-    
-    /** The global registries */
-    private final transient Registries registries;
+    /** The AttributeType registries */
+    private final transient AttributeTypeRegistry atRegistry;
     
     /** A speedup to get the ObjectClass attribute */
     private static transient AttributeType OBJECT_CLASS_AT;
     
-    /** The DN for this entry */
-    private LdapDN dn;
-    
     /** A mutex to manage synchronization*/
     private transient static Object MUTEX = new Object();
 
 
+    //-------------------------------------------------------------------------
+    // Helper methods
+    //-------------------------------------------------------------------------
+    /**
+     * Returns the attributeType from an Attribute ID.
+     */
+    private AttributeType getAttributeType( String upId ) throws NamingException
+    {
+        if ( StringTools.isEmpty( StringTools.trim( upId ) ) )
+        {
+            String message = "The ID should not be null or empty";
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+        
+        return atRegistry.lookup( upId );
+    }
+
+    
+    /**
+     * Get the UpId if it was null.
+     */
+    public static String getUpId( String upId, AttributeType attributeType ) throws NamingException
+    {
+        String normUpId = StringTools.trim( upId );
+
+        if ( ( attributeType == null ) )
+        {
+            if ( StringTools.isEmpty( normUpId ) )
+            {
+                String message = "Cannot add an attribute without an ID";
+                LOG.error( message );
+                throw new IllegalArgumentException( message );
+            }
+        }
+        else if ( StringTools.isEmpty( normUpId ) )
+        {
+            upId = attributeType.getName();
+            
+            if ( StringTools.isEmpty( upId ) )
+            {
+                upId = attributeType.getOid();
+            }
+        }
+        
+        return upId;
+    }
+
+    
     /**
      * This method is used to initialize the OBJECT_CLASS_AT attributeType.
      * 
@@ -98,7 +142,7 @@
             {
                 synchronized ( MUTEX )
                 {
-                    OBJECT_CLASS_AT = registries.getAttributeTypeRegistry().lookup( SchemaConstants.OBJECT_CLASS_AT );
+                    OBJECT_CLASS_AT = atRegistry.lookup( SchemaConstants.OBJECT_CLASS_AT );
                 }
             }
         }
@@ -110,23 +154,91 @@
 
     
     /**
-     * Creates a new instance of DefaultServerEntry. This is a private constructor
-     * which will only be used by the desrialization method 
+     * Add a new ServerAttribute, with its upId. If the upId is null,
+     * default to the AttributeType name.
+     * 
+     * Updates the serverAttributeMap.
+     */
+    private void createAttribute( String upId, AttributeType attributeType, byte[]... values ) throws NamingException, InvalidAttributeValueException
+    {
+        ServerAttribute attribute = new DefaultServerAttribute( attributeType, values );
+        attribute.setUpId( upId, attributeType );
+        attributes.put( attributeType, attribute );
+    }
+    
+    
+    /**
+     * Add a new ServerAttribute, with its upId. If the upId is null,
+     * default to the AttributeType name.
+     * 
+     * Updates the serverAttributeMap.
+     */
+    private void createAttribute( String upId, AttributeType attributeType, String... values ) throws NamingException, InvalidAttributeValueException
+    {
+        ServerAttribute attribute = new DefaultServerAttribute( attributeType, values );
+        attribute.setUpId( upId, attributeType );
+        attributes.put( attributeType, attribute );
+    }
+    
+    
+    /**
+     * Add a new ServerAttribute, with its upId. If the upId is null,
+     * default to the AttributeType name.
+     * 
+     * Updates the serverAttributeMap.
+     */
+    private void createAttribute( String upId, AttributeType attributeType, Value<?>... values ) throws NamingException, InvalidAttributeValueException
+    {
+        ServerAttribute attribute = new DefaultServerAttribute( attributeType, values );
+        attribute.setUpId( upId, attributeType );
+        attributes.put( attributeType, attribute );
+    }
+    
+    
+    //-------------------------------------------------------------------------
+    // Constructors
+    //-------------------------------------------------------------------------
+    /**
+     * <p>
+     * Creates a new instance of DefaultServerEntry.
+     * </p> 
      * <p>
      * This entry <b>must</b> be initialized before being used !
+     * </p>
+     */
+    /* no protection ! */ DefaultServerEntry()
+    {
+        atRegistry = null;
+    }
+
+
+    /**
+     * <p>
+     * Creates a new instance of DefaultServerEntry, with registries. 
+     * </p>
+     * <p>
+     * No attributes will be created.
+     * </p> 
+     * 
+     * @param registries The reference to the global registries
      */
-    public DefaultServerEntry()
+    public DefaultServerEntry( Registries registries )
     {
-        registries = null;
+        this.atRegistry = registries.getAttributeTypeRegistry();
+
+        // Initialize the ObjectClass object
+        initObjectClassAT( registries );
     }
 
 
     /**
+     * <p>
      * Creates a new instance of DefaultServerEntry, with a 
      * DN and registries. 
+     * </p>
      * <p>
-     * No attributes will be created except the ObjectClass attribute,
-     * which will contains "top". 
+     * No attributes will be created.
+     * </p> 
      * 
      * @param registries The reference to the global registries
      * @param dn The DN for this serverEntry. Can be null.
@@ -134,20 +246,25 @@
     public DefaultServerEntry( Registries registries, LdapDN dn )
     {
         this.dn = dn;
-        this.registries = registries;
+        this.atRegistry = registries.getAttributeTypeRegistry();
 
+        // Initialize the ObjectClass object
         initObjectClassAT( registries );
     }
 
 
     /**
+     * <p>
      * Creates a new instance of DefaultServerEntry, with a 
      * DN, registries and a list of attributeTypes. 
+     * </p>
      * <p>
-     * No attributes will be created except the ObjectClass attribute,
-     * which will contains "top". 
+     * The newly created entry is fed with the list of attributeTypes. No
+     * values are associated with those attributeTypes.
+     * </p>
      * <p>
-     * If any of the AttributeType does not exist, they are simply discarded.
+     * If any of the AttributeType does not exist, they it's simply discarded.
+     * </p>
      * 
      * @param registries The reference to the global registries
      * @param dn The DN for this serverEntry. Can be null.
@@ -156,28 +273,31 @@
     public DefaultServerEntry( Registries registries, LdapDN dn, AttributeType... attributeTypes )
     {
         this.dn = dn;
-        this.registries = registries;
+        this.atRegistry = registries.getAttributeTypeRegistry();
 
+        // Initialize the ObjectClass object
         initObjectClassAT( registries );
 
-        for ( AttributeType attributeType:attributeTypes )
-        {
-            // Add a new AttributeType without value
-            set( attributeType );
-        }
+        // Add the attributeTypes
+        set( attributeTypes );
     }
 
     
     /**
+     * <p>
      * Creates a new instance of DefaultServerEntry, with a 
      * DN, registries and an attributeType with the user provided ID. 
+     * </p>
      * <p>
-     * No attributes will be created except the ObjectClass attribute,
-     * which will contains "top". 
+     * The newly created entry is fed with the given attributeType. No
+     * values are associated with this attributeType.
+     * </p>
      * <p>
-     * If the AttributeType does not exist, then an empty Entry is created.
+     * If the AttributeType does not exist, they it's simply discarded.
+     * </p>
      * <p>
      * We also check that the normalized upID equals the AttributeType ID
+     * </p>
      * 
      * @param registries The reference to the global registries
      * @param dn The DN for this serverEntry. Can be null.
@@ -187,8 +307,10 @@
     public DefaultServerEntry( Registries registries, LdapDN dn, AttributeType attributeType, String upId )
     {
         this.dn = dn;
-        this.registries = registries;
+        this.atRegistry = registries.getAttributeTypeRegistry();
+        // Initialize the ObjectClass object
 
+        // Initialize the ObjectClass object
         initObjectClassAT( registries );
 
         try
@@ -197,11 +319,11 @@
         }
         catch ( NamingException ne )
         {
-            // What do we do ???
+            // Just discard the AttributeType
             LOG.error( "We have had an error while adding the '{}' AttributeType : {}", upId, ne.getMessage() );
         }
     }
-
+    
     
     /**
      * Creates a new instance of DefaultServerEntry, with a 
@@ -219,31 +341,11 @@
     public DefaultServerEntry( Registries registries, LdapDN dn, String... upIds )
     {
         this.dn = dn;
-        this.registries = registries;
+        this.atRegistry = registries.getAttributeTypeRegistry();
 
         initObjectClassAT( registries );
 
-        for ( String upId:upIds )
-        {
-            try
-            {
-                AttributeType attributeType = registries.getAttributeTypeRegistry().lookup( upId );
-                
-                if ( attributeType.equals(  OBJECT_CLASS_AT ) )
-                {
-                    // The ObjectClass AttributeType has already been added
-                    continue;
-                }
-                
-                // Add a new AttributeType without value
-                set( upId );
-            }
-            catch ( NamingException ne )
-            {
-                // Just log an error...
-                LOG.error( "The '{}' AttributeType does not exist", upId );
-            }
-        }
+        set( upIds );
     }
 
     
@@ -263,7 +365,7 @@
     public DefaultServerEntry( Registries registries, LdapDN dn, ServerAttribute... attributes )
     {
         this.dn = dn;
-        this.registries = registries;
+        this.atRegistry = registries.getAttributeTypeRegistry();
 
         initObjectClassAT( registries );
 
@@ -283,419 +385,945 @@
 
     
     //-------------------------------------------------------------------------
-    // Helper methods
+    // API
     //-------------------------------------------------------------------------
-    
     /**
-     * Returns the attributeType from an Attribute ID.
+     * <p>
+     * Add an attribute (represented by its AttributeType and some binary values) into an 
+     * entry.
+     * </p>
+     * <p> 
+     * If we already have an attribute with the same values, nothing is done 
+     * (duplicated values are not allowed)
+     * </p>
+     * <p>
+     * If the value cannot be added, or if the AttributeType is null or invalid, 
+     * a NamingException is thrown.
+     * </p>
+     *
+     * @param attributeType The attribute Type.
+     * @param values The list of binary values to inject. It can be empty.
+     * @throws NamingException If the attribute does not exist
      */
-    private AttributeType getAttributeType( String upId ) throws NamingException
+    public void add( AttributeType attributeType, byte[]... values ) throws NamingException
     {
-        if ( StringTools.isEmpty( StringTools.trim( upId ) ) )
+        if ( attributeType == null )
+        {
+            String message = "The attributeType should not be null";
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+        
+        // ObjectClass with binary values are not allowed
+        if ( attributeType.equals( OBJECT_CLASS_AT ) )
+        {
+            String message = "Only String values supported for objectClass attribute";
+            LOG.error(  message  );
+            throw new UnsupportedOperationException( message );
+        }
+
+        EntryAttribute attribute = attributes.get( attributeType );
+        
+        if ( attribute != null )
+        {
+            // This Attribute already exist, we add the values 
+            // into it
+            attribute.add( values );
+        }
+        else
+        {
+            // We have to create a new Attribute and set the values.
+            // The upId, which is set to null, will be setup by the 
+            // createAttribute method
+            createAttribute( null, attributeType, values );
+        }
+    }
+
+
+    /**
+     * <p>
+     * Add an attribute (represented by its AttributeType and some String values) into an 
+     * entry.
+     * </p>
+     * <p> 
+     * If we already have an attribute with public the same value, nothing is done 
+     * (duplicated values are not allowed)
+     * </p>
+     * <p>public 
+     * If the value cannot be added, or if the AttributeType is null or invalid, 
+     * a NamingException is thrown.
+     * </p>
+     *public 
+     * @param attributeType The attribute Type
+     * @param values The list of binary values to inject. It can be empty
+     * @throws NamingException If the attribute does not exist
+     */
+    public void add( AttributeType attributeType, String... values ) throws NamingException
+    {    
+        if ( attributeType == null )
         {
-            String message = "The ID should not be null";
+            String message = "The attributeType should not be null";
             LOG.error( message );
             throw new IllegalArgumentException( message );
         }
         
-        return registries.getAttributeTypeRegistry().lookup( upId );
+        EntryAttribute attribute = attributes.get( attributeType );
+        
+        if ( attribute != null )
+        {
+            // This Attribute already exist, we add the values 
+            // into it
+            attribute.add( values );
+        }
+        else
+        {
+            // We have to create a new Attribute and set the values.
+            // The upId, which is set to null, will be setup by the 
+            // createAttribute method
+            createAttribute( null, attributeType, values );
+        }
     }
 
     
     /**
-     * Get the UpId if it was null.
+     * <p>
+     * Add an attribute (represented by its AttributeType and some values) into an 
+     * entry.
+     * </p>
+     * <p> 
+     * If we already have an attribute with the same value, nothing is done.
+     * (duplicated values are not allowed)
+     * </p>
+     * <p>
+     * If the value cannot be added, or if the AttributeType is null or invalid, 
+     * a NamingException is thrown.
+     * </p>
+     *
+     * @param attributeType The attribute Type
+     * @param values The list of binary values to inject. It can be empty
+     * @throws NamingException If the attribute does not exist
      */
-    public static String getUpId( String upId, AttributeType attributeType ) throws NamingException
+    public void add( AttributeType attributeType, Value<?>... values ) throws NamingException
     {
-        String normUpId = StringTools.trim( upId );
-
-        if ( ( attributeType == null ) )
+        if ( attributeType == null )
         {
-            if ( StringTools.isEmpty( normUpId ) )
-            {
-                String message = "Cannot add an attribute without an ID";
-                LOG.error( message );
-                throw new IllegalArgumentException( message );
-            }
+            String message = "The attributeType should not be null";
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
         }
-        else if ( StringTools.isEmpty( normUpId ) )
+        
+        EntryAttribute attribute = attributes.get( attributeType );
+    
+        if ( attribute != null )
         {
-            upId = attributeType.getName();
-            
-            if ( StringTools.isEmpty( upId ) )
-            {
-                upId = attributeType.getOid();
-            }
+            // This Attribute already exist, we add the values 
+            // into it
+            attribute.add( values );
+        }
+        else
+        {
+            // We have to create a new Attribute and set the values.
+            // The upId, which is set to null, will be setup by the 
+            // createAttribute method
+            createAttribute( null, attributeType, values );
         }
-        
-        return upId;
     }
 
-    
+
     /**
-     * Get the attributeType from the UpId if null.
+     * Add some EntryAttributes to the current Entry.
+     *
+     * @param attributes The attributes to add
+     * @throws NamingException If we can't add any of the attributes
      */
-    private AttributeType getAttributeType( String upId, AttributeType attributeType ) throws NamingException
+    public void add( EntryAttribute... attributes ) throws NamingException
     {
-        if ( ( attributeType == null ) )
+        for ( EntryAttribute attribute:attributes )
         {
-            String normUpId = StringTools.trim( upId );
+            ServerAttribute serverAttribute = (ServerAttribute)attribute;
+            AttributeType attributeType = serverAttribute.getAttributeType();
             
-            if ( StringTools.isEmpty( normUpId ) )
+            if ( this.attributes.containsKey( attributeType ) )
             {
-                String message = "Cannot add an attribute without an ID";
-                LOG.error( message );
-                throw new IllegalArgumentException( message );
+                // We already have an attribute with the same AttributeType
+                // Just add the new values into it.
+                EntryAttribute oldAttribute = this.attributes.get( attributeType );
+                
+                for ( Value<?> value:serverAttribute )
+                {
+                    oldAttribute.add( value );
+                }
+                
+                // And update the upId
+                oldAttribute.setUpId( serverAttribute.getUpId() );
             }
             else
             {
-                attributeType = registries.getAttributeTypeRegistry().lookup( upId );
+                // The attributeType does not exist, add it
+                this.attributes.put( attributeType, attribute );
             }
         }
-        
-        return attributeType;
     }
 
-    
-    public boolean hasObjectClass( String objectClass )
-    {
-        ServerAttribute oc = serverAttributeMap.get( OBJECT_CLASS_AT );
-        
-        return oc.contains( objectClass );
-    }
 
-    public boolean isValid()
-    {
-        throw new NotImplementedException();
+    /**
+     * <p>
+     * Add an attribute (represented by its AttributeType and some binary values) into an 
+     * entry. Set the User Provider ID at the same time
+     * </p>
+     * <p> 
+     * If we already have an attribute with the same values, nothing is done 
+     * (duplicated values are not allowed)
+     * </p>
+     * <p>
+     * If the value cannot be added, or if the AttributeType is null or invalid, 
+     * a NamingException is thrown.
+     * </p>
+     *
+     * @param upId The user provided ID for the added AttributeType
+     * @param attributeType The attribute Type.
+     * @param values The list of binary values to add. It can be empty.
+     * @throws NamingException If the attribute does not exist
+     */
+    public void add( String upId, AttributeType attributeType, byte[]... values ) throws NamingException
+    {
+        // ObjectClass with binary values are not allowed
+        if ( attributeType.equals( OBJECT_CLASS_AT ) )
+        {
+            String message = "Only String values supported for objectClass attribute";
+            LOG.error(  message  );
+            throw new UnsupportedOperationException( message );
+        }
+
+        ServerAttribute attribute = (ServerAttribute)attributes.get( attributeType );
+        
+        upId = getUpId( upId, attributeType );
+        
+        if ( attribute != null )
+        {
+            // This Attribute already exist, we add the values 
+            // into it
+            attribute.add( values );
+            attribute.setUpId( upId, attributeType );
+        }
+        else
+        {
+            // We have to create a new Attribute and set the values
+            // and the upId
+            createAttribute( upId, attributeType, values );
+        }
     }
 
 
-    public boolean isValid( ObjectClass objectClass )
+    /**
+     * <p>
+     * Add an attribute (represented by its AttributeType and some values) into an 
+     * entry. Set the User Provider ID at the same time
+     * </p>
+     * <p> 
+     * If we already have an attribute with the same values, nothing is done 
+     * (duplicated values are not allowed)
+     * </p>
+     * <p>
+     * If the value cannot be added, or if the AttributeType is null or invalid, 
+     * a NamingException is thrown.
+     * </p>
+     *
+     * @param upId The user provided ID for the added AttributeType
+     * @param attributeType The attribute Type.
+     * @param values The list of values to add. It can be empty.
+     * @throws NamingException If the attribute does not exist
+     */
+    public void add( String upId, AttributeType attributeType, Value<?>... values ) throws NamingException
     {
-        throw new NotImplementedException();
+        if ( attributeType == null )
+        {
+            String message = "The attributeType should not be null";
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+        
+        upId = getUpId( upId, attributeType );
+        
+        ServerAttribute attribute = (ServerAttribute)attributes.get( attributeType );
+    
+        if ( attribute != null )
+        {
+            // This Attribute already exist, we add the values 
+            // into it
+            attribute.add( values );
+            attribute.setUpId( upId, attributeType );
+        }
+        else
+        {
+            createAttribute( upId, attributeType, values );
+        }
     }
 
-
+    
     /**
-     * Returns the attribute associated with an AttributeType
-     * 
-     * @param attributeType the AttributeType we are looking for
-     * @return the associated attribute
+     * Adds a new attribute with some String values into an entry, setting
+     * the User Provided ID in the same time.
+     *
+     * @param upId The User provided ID
+     * @param attributeType The associated AttributeType
+     * @param values The String values to store into the new Attribute
+     * @throws NamingException 
      */
-    public ServerAttribute get( AttributeType attributeType )
+    public void add( String upId, AttributeType attributeType, String... values ) throws NamingException
     {
-        return serverAttributeMap.get( attributeType );
+        if ( attributeType == null )
+        {
+            String message = "The attributeType should not be null";
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
+        }
+        
+        upId = getUpId( upId, attributeType );
+
+        ServerAttribute attribute = (ServerAttribute)attributes.get( attributeType );
+        
+        if ( attribute != null )
+        {
+            // This Attribute already exist, we add the values 
+            // into it
+            attribute.add( values );
+            attribute.setUpId( upId, attributeType );
+        }
+        else
+        {
+            // We have to create a new Attribute and set the values
+            // and the upId
+            createAttribute( upId, attributeType, values );
+        }
+    }
+
+
+    /**                 
+     * Add an attribute (represented by its ID and binary values) into an entry. 
+     *
+     * @param upId The attribute ID
+     * @param values The list of binary values to inject. It can be empty
+     * @throws NamingException If the attribute does not exist
+     */
+    public void add( String upId, byte[]... values ) throws NamingException
+    {
+        add( upId, getAttributeType( upId ), values );
     }
 
 
     /**
-     * Returns the attribute associated with a String
-     * 
-     * @param attributeType the Attribute ID we are looking for
-     * @return the associated attribute
+     * Add an attribute (represented by its ID and string values) into an entry. 
+     *
+     * @param upId The attribute ID
+     * @param values The list of string values to inject. It can be empty
+     * @throws NamingException If the attribute does not exist
      */
-    public ServerAttribute get( String attributeType ) throws NamingException
+    public void add( String upId, String... values ) throws NamingException
     {
-        return get( registries.getAttributeTypeRegistry().lookup( attributeType ) );
+        add( upId, getAttributeType( upId ), values );
     }
 
 
     /**
-     * Put an attribute (represented by its ID and values) into an entry. 
-     * If the attribute already exists, the previous attribute will be 
-     * replaced and returned.
+     * Add an attribute (represented by its ID and Value values) into an entry. 
      *
      * @param upId The attribute ID
-     * @param values The list of values to inject. It can be empty
-     * @return The replaced attribute
+     * @param values The list of Value values to inject. It can be empty
      * @throws NamingException If the attribute does not exist
      */
-    public ServerAttribute put( String upId, String... values ) throws NamingException
+    public void add( String upId, Value<?>... values ) throws NamingException
     {
-        return put( upId, getAttributeType( upId ), values );
+        add( upId, getAttributeType( upId ), values );
     }
 
 
     /**
-     * Put an attribute (represented by its ID and values) into an entry. 
-     * If the attribute already exists, the previous attribute will be 
-     * replaced and returned.
+     * Checks if an entry contains an attribute with some given binary values.
+     *
+     * @param attributeType The Attribute we are looking for.
+     * @param values The searched values.
+     * @return <code>true</code> if all the values are found within the attribute,
+     * <code>false</code> otherwise, or if the attributes does not exist.
+     */
+    public boolean contains( AttributeType attributeType, byte[]... values )
+    {
+        if ( attributeType == null )
+        {
+            return false;
+        }
+        
+        EntryAttribute attribute = attributes.get( attributeType );
+        
+        if ( attribute != null )
+        {
+            return attribute.contains( values );
+        }
+        else
+        {
+            return false;
+        }
+    }
+    
+    
+    /**
+     * Checks if an entry contains an attribute with some given String values.
+     *
+     * @param attributeType The Attribute we are looking for.
+     * @param values The searched values.
+     * @return <code>true</code> if all the values are found within the attribute,
+     * <code>false</code> otherwise, or if the attributes does not exist.
+     */
+    public boolean contains( AttributeType attributeType, String... values )
+    {
+        if ( attributeType == null )
+        {
+            return false;
+        }
+
+        EntryAttribute attribute = attributes.get( attributeType );
+        
+        if ( attribute != null )
+        {
+            return attribute.contains( values );
+        }
+        else
+        {
+            return false;
+        }
+    }
+    
+    
+    /**
+     * Checks if an entry contains an attribute with some given binary values.
+     *
+     * @param attributeType The Attribute we are looking for.
+     * @param values The searched values.
+     * @return <code>true</code> if all the values are found within the attribute,
+     * <code>false</code> otherwise, or if the attributes does not exist.
+     */
+    public boolean contains( AttributeType attributeType, Value<?>... values )
+    {
+        if ( attributeType == null )
+        {
+            return false;
+        }
+        
+        EntryAttribute attribute = attributes.get( attributeType );
+        
+        if ( attribute != null )
+        {
+            return attribute.contains( values );
+        }
+        else
+        {
+            return false;
+        }
+    }
+    
+    
+    /**
+     * <p>
+     * Checks if an entry contains a list of attributes.
+     * </p>
+     * <p>
+     * If the list is null or empty, this method will return <code>true</code>
+     * if the entry has no attribute, <code>false</code> otherwise.
+     * </p>
+     *
+     * @param attributes The Attributes to look for
+     * @return <code>true</code> if all the attributes are found within 
+     * the entry, <code>false</code> if at least one of them is not present.
+     * @throws NamingException If the attribute does not exist
+     */
+    public boolean contains( EntryAttribute... attributes ) throws NamingException
+    {
+        for ( EntryAttribute entryAttribute:attributes )
+        {
+            if ( entryAttribute == null )
+            {
+                return this.attributes.size() == 0;
+            }
+            
+            if ( !this.attributes.containsKey( ((ServerAttribute)entryAttribute).getAttributeType() ) )
+            {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+
+
+    /**
+     * Checks if an entry contains an attribute with some binary values.
+     *
+     * @param id The Attribute we are looking for.
+     * @param values The searched values.
+     * @return <code>true</code> if all the values are found within the attribute,
+     * false if at least one value is not present or if the ID is not valid. 
+     */
+    public boolean contains( String id, byte[]... values )
+    {
+        if ( id == null )
+        {
+            return false;
+        }
+        
+        try
+        {
+            AttributeType attributeType = atRegistry.lookup( id );
+            
+            if ( attributeType == null )
+            {
+                return false;
+            }
+            
+            EntryAttribute attribute = attributes.get( attributeType );
+            
+            if ( attribute != null )
+            {
+                return attribute.contains( values );
+            }
+            else
+            {
+                return false;
+            }
+        }
+        catch ( NamingException ne )
+        {
+            return false;
+        }
+    }
+    
+    
+    /**
+     * Checks if an entry contains an attribute with some String values.
+     *
+     * @param id The Attribute we are looking for.
+     * @param values The searched values.
+     * @return <code>true</code> if all the values are found within the attribute,
+     * false if at least one value is not present or if the ID is not valid. 
+     */
+    public boolean contains( String id, String... values )
+    {
+        if ( id == null )
+        {
+            return false;
+        }
+        
+        try
+        {
+            AttributeType attributeType = atRegistry.lookup( id );
+            
+            if ( attributeType == null )
+            {
+                return false;
+            }
+            
+            EntryAttribute attribute = attributes.get( attributeType );
+            
+            if ( attribute != null )
+            {
+                return attribute.contains( values );
+            }
+            else
+            {
+                return false;
+            }
+        }
+        catch ( NamingException ne )
+        {
+            return false;
+        }
+    }
+    
+    
+    /**
+     * Checks if an entry contains an attribute with some values.
+     *
+     * @param id The Attribute we are looking for.
+     * @param values The searched values.
+     * @return <code>true</code> if all the values are found within the attribute,
+     * false if at least one value is not present or if the ID is not valid. 
+     */
+    public boolean contains( String id, Value<?>... values )
+    {
+        if ( id == null )
+        {
+            return false;
+        }
+        
+        try
+        {
+            AttributeType attributeType = atRegistry.lookup( id );
+            
+            if ( attributeType == null )
+            {
+                return false;
+            }
+
+            EntryAttribute attribute = attributes.get( attributeType );
+            
+            if ( attribute != null )
+            {
+                return attribute.contains( values );
+            }
+            else
+            {
+                return false;
+            }
+        }
+        catch ( NamingException ne )
+        {
+            return false;
+        }
+    }
+    
+    
+    /**
+     * Checks if an entry contains a specific AttributeType.
+     *
+     * @param attributeType The AttributeType to look for.
+     * @return <code>true</code> if the attribute is found within the entry.
+     */
+    public boolean containsAttribute( AttributeType attributeType )
+    {
+        return attributes.containsKey( attributeType );
+    }
+
+    
+    /**
+     * Checks if an entry contains some specific attributes.
+     *
+     * @param attributes The Attributes to look for.
+     * @return <code>true</code> if the attributes are all found within the entry.
+     */
+    public boolean containsAttribute( String... attributes )
+    {
+        for ( String attribute:attributes )
+        {
+            try
+            {
+                if ( !this.attributes.containsKey( getAttributeType( attribute ) ) )
+                {
+                    return false;
+                }
+            }
+            catch ( NamingException ne )
+            {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+
+    
+    /**
+     * <p>
+     * Returns the attribute with the specified AttributeType. The return value
+     * is <code>null</code> if no match is found.  
+     * </p>
      *
-     * @param upId The attribute ID
-     * @param values The list of values to inject. It can be empty.
-     * @return The replaced attribute
-     * @throws NamingException If the attribute does not exist
+     * @param attributeType The attributeType we are looking for.
+     * @return the attribute associated with the AttributeType.
+     */
+    /**
+     * Returns the attribute associated with an AttributeType
+     * 
+     * @param the AttributeType we are looking for
+     * @return the associated attribute
      */
-    public ServerAttribute put( String upId, byte[]... values ) throws NamingException
+    public EntryAttribute get( AttributeType attributeType )
     {
-        return put( upId, getAttributeType( upId ), values );
+        return attributes.get( attributeType );
     }
 
 
     /**
-     * Set some new empty AttributeTypes into the serverEntry.
      * <p>
-     * If there is already a ServerAttribute with the same AttributeType, 
-     * it will be removed from the entry and returned back to the caller.
-     * 
-     * @param attributeTypes the new ServerAttribute attributeType to be added
-     * @return The list of existing ServerAttribute, if any with the same AttributeType
+     * Returns the attribute with the specified alias. The return value
+     * is <code>null</code> if no match is found.  
+     * </p>
+     * <p>An Attribute with an id different from the supplied alias may 
+     * be returned: for example a call with 'cn' may in some implementations 
+     * return an Attribute whose getId() field returns 'commonName'.
+     * </p>
+     * <p>
+     * If the attributeType is not found, returns null.
+     * </p>
+     *
+     * @param alias an aliased name of the attribute identifier
+     * @return the attribute associated with the alias
      */
-    public List<ServerAttribute> set( AttributeType... attributeTypes )
+    public EntryAttribute get( String alias )
     {
-        if ( attributeTypes == null )
+        try
         {
-            String message = "The AttributeType list should not be null";
-            LOG.error( message );
-            throw new IllegalArgumentException( message );
+            return get( atRegistry.lookup( alias ) );
         }
-        
-        List<ServerAttribute> returnedServerAttributes = null;
-        
-        // Now, loop on all the attributeType to add
-        for ( AttributeType attributeType:attributeTypes )
+        catch ( NamingException ne )
         {
-            if ( attributeType == null )
-            {
-                String message = "The AttributeType list should not contain null values";
-                LOG.error( message );
-                throw new IllegalArgumentException( message );
-            }
-            
-            if ( returnedServerAttributes == null )
-            {
-                returnedServerAttributes = new ArrayList<ServerAttribute>();
-            }
-
-            if ( serverAttributeMap.containsKey( attributeType ) )
-            {
-                // Add the removed serverAttribute to the list
-                returnedServerAttributes.add( serverAttributeMap.remove( attributeType ) );
-            }
-
-            ServerAttribute newAttribute = new DefaultServerAttribute( attributeType );
-            serverAttributeMap.put( attributeType, newAttribute );
+            String message = ne.getMessage();
+            LOG.error( message );
+            return null;
         }
-        
-        return returnedServerAttributes;
     }
 
+
+    /**
+     * Gets all the attributes type
+     *
+     * @return The combined set of all the attributes, including ObjectClass.
+     */
+    public Set<AttributeType> getAttributeTypes()
+    {
+        return attributes.keySet();
+    }
+    
     
     /**
-     * Put some new empty ServerAttribute into the serverEntry. 
-     * <p>
-     * If there is already a ServerAttribute with the same AttributeType, 
-     * it will be removed from the entry and returned back to the caller.
-     * <p>
-     * The added ServerAttributes are supposed to be valid.
+     * Tells if an entry has a specific ObjectClass value
      * 
-     * @param serverAttributes the new ServerAttributes to put into the serverEntry
-     * @return An existing ServerAttribute, if any of the added serverAttribute 
-     * already exists
+     * @param objectClass The ObjectClass ID we want to check
+     * @return <code>true</code> if the ObjectClass value is present 
+     * in the ObjectClass attribute
      */
-    public List<ServerAttribute> put( ServerAttribute... serverAttributes ) throws NamingException
+    public boolean hasObjectClass( String objectClass )
     {
-        List<ServerAttribute> previous = new ArrayList<ServerAttribute>();
-        
-        for ( ServerAttribute serverAttribute:serverAttributes )
-        {
-            if ( serverAttribute == null )
-            {
-                String message = "The ServerAttribute list should not contain null elements";
-                LOG.error( message );
-                throw new IllegalArgumentException( message );
-            }
-            
-            ServerAttribute removed = serverAttributeMap.put( serverAttribute.getAttributeType(), serverAttribute );
-            
-            if ( removed != null )
-            {
-                previous.add( removed );
-            }
-        }
-        
-        return previous;
+        return contains( OBJECT_CLASS_AT, objectClass );
     }
 
-
+    
     /**
-     * Put some new ServerAttribute using the User Provided ID to select
-     * the AttributeType. No value is inserted.
-     * 
-     * @param upIds The user provided IDs of the AttributeTypes to add.
-     * @return A list of existing ServerAttribute, if any with the same 
-     * AttributeType
+     * Tells if an entry has a specific ObjectClass Attribute
      * 
-     * @throws NamingException If one of the user provided ID is not an 
-     * attributeType's name
+     * @param objectClass The ObjectClass we want to check
+     * @return <code>true</code> if the ObjectClass value is present 
+     * in the ObjectClass attribute
      */
-    public List<ServerAttribute> set( String... upIds ) throws NamingException
+    public boolean hasObjectClass( EntryAttribute objectClass )
     {
-        List<ServerAttribute> existings = null;
+        if ( objectClass == null )
+        {
+            return false;
+        }
         
-        for ( String upId:upIds )
+        // We have to check that we are checking the ObjectClass attributeType
+        if ( ((ServerAttribute)objectClass).getAttributeType() != OBJECT_CLASS_AT )
         {
-            // Search for the corresponding AttributeType, based on the upID 
-            AttributeType attributeType = getAttributeType( upId );
-            
-            ServerAttribute existing = serverAttributeMap.put( attributeType, 
-                new DefaultServerAttribute( upId, attributeType ));
-            
-            if ( existing != null )
-            {
-                if ( existings == null )
-                {
-                    existings = new ArrayList<ServerAttribute>();
-                }
-                
-                existings.add( existing );
-            }
+            return false;
         }
         
-        return existings;
-    }
-
-
-    public List<ServerAttribute> remove( ServerAttribute... serverAttributes ) throws NamingException
-    {
-        List<ServerAttribute> removedAttributes = new ArrayList<ServerAttribute>();
+        EntryAttribute attribute = attributes.get( OBJECT_CLASS_AT );
+        
+        if ( attribute == null )
+        {
+            // The entry does not have an ObjectClass attribute
+            return false;
+        }
         
-        for ( ServerAttribute serverAttribute:serverAttributes )
+        for ( Value<?> value:objectClass )
         {
-            if ( serverAttributeMap.containsKey( serverAttribute.getAttributeType() ) )
+            // Loop on all the values, and check if they are present
+            if ( !attribute.contains( value ) )
             {
-                serverAttributeMap.remove( serverAttribute.getAttributeType() );
-                removedAttributes.add( serverAttribute );
+                return false;
             }
         }
         
-        return removedAttributes;
+        return true;
     }
 
-
+    
     /**
-     * Stores a new attribute with some values into the entry.
-     * <p>
-     * The previous attribute with the same attributeType, if any, is returned.
-     * 
-     * @param attributeType The attributeType to add
-     * @param values The associated values
-     * @return The existing ServerAttribute, if any
-     * @throws NamingException If some values conflict with the attributeType
-     * 
+     * Fail fast check performed to determine entry consistency according to schema
+     * characteristics.
+     *
+     * @return true if the entry, it's attributes and their values are consistent
+     * with the schema
      */
-    public ServerAttribute put( AttributeType attributeType, Value<?>... values ) throws NamingException
+    public boolean isValid()
     {
-        return put( null, attributeType, values );
+        // @TODO Implement me !
+        throw new NotImplementedException();
     }
 
 
     /**
-     * Stores a new attribute with some values into an entry, setting
-     * the User Provided ID in the same time.
-     *
-     * @param upId The User provided ID
-     * @param attributeType The associated AttributeType
-     * @param values The values to store into the new Attribute
-     * @return The existing attribute if any
-     * @throws NamingException 
+     * Check performed to determine entry consistency according to the schema
+     * requirements of a particular objectClass.  The entry must be of that objectClass
+     * to return true: meaning if the entry's objectClass attribute does not contain
+     * the objectClass argument, then false should be returned.
+     *
+     * @param objectClass the objectClass to use while checking for validity
+     * @return true if the entry, it's attributes and their values are consistent
+     * with the objectClass
      */
-    public ServerAttribute put( String upId, AttributeType attributeType, Value<?>... values ) throws NamingException
+    public boolean isValid( EntryAttribute objectClass )
     {
-        upId = getUpId( upId, attributeType );
-        attributeType = getAttributeType( upId, attributeType );
+        // @TODO Implement me !
+        throw new NotImplementedException();
+    }
+
 
-        // We simply have to set the current attribute values
-        ServerAttribute serverAttribute = new DefaultServerAttribute( upId, attributeType, values );
-        return serverAttributeMap.put( attributeType, serverAttribute );
+    /**
+     * Check performed to determine entry consistency according to the schema
+     * requirements of a particular objectClass.  The entry must be of that objectClass
+     * to return true: meaning if the entry's objectClass attribute does not contain
+     * the objectClass argument, then false should be returned.
+     *
+     * @param objectClass the objectClass to use while checking for validity
+     * @return true if the entry, it's attributes and their values are consistent
+     * with the objectClass
+     */
+    public boolean isValid( String objectClass )
+    {
+        // @TODO Implement me !
+        throw new NotImplementedException();
     }
 
 
     /**
-     * Put an attribute (represented by its ID and some values) into an entry. 
-     * If the attribute already exists, the previous attribute will be 
-     * replaced and returned.
      * <p>
-     * The values are stored as Value<?> objects.
-     *
-     * @param upId The attribute ID
-     * @param values The list of Value<?> objects to inject. It can be empty.
-     * @return The replaced attribute
-     * @throws NamingException If the attribute does not exist
+     * Places a new attribute with the supplied AttributeType and binary values 
+     * into the attribute collection. 
+     * </p>
+     * <p>
+     * If there is already an attribute with the same AttributeType, the old
+     * one is removed from the collection and is returned by this method. 
+     * </p>
+     * <p>
+     * This method provides a mechanism to put an attribute with a
+     * <code>null</code> value: the value may be <code>null</code>.
+     *
+     * @param attributeType the type of the new attribute to be put
+     * @param values the binary values of the new attribute to be put
+     * @return the old attribute with the same identifier, if exists; otherwise
+     * <code>null</code>
+     * @throws NamingException if there are failures
      */
-    public ServerAttribute put( String upId, Value<?>... values ) throws NamingException
+    public EntryAttribute put( AttributeType attributeType, byte[]... values ) throws NamingException
     {
-        return put( upId, getAttributeType( upId ), values );
+        return put( null, attributeType, values );
     }
 
 
     /**
-     * Stores a new attribute, creating it from its attributeType and String values.
      * <p>
-     * The values are Strings, so the attributeType must be humanReadable. Otherwise,
-     * we will try to convert values from String to byte[]
-     * 
-     * @param attributeType The attributeType
-     * @param values The String values to add to the attribute
-     * @return The existing ServerAttribute which has been replaced, if any
-     * @throws NamingException If some values conflict with the attributeType
+     * Places a new attribute with the supplied AttributeType and String values 
+     * into the attribute collection. 
+     * </p>
+     * <p>
+     * If there is already an attribute with the same AttributeType, the old
+     * one is removed from the collection and is returned by this method. 
+     * </p>
+     * <p>
+     * This method provides a mechanism to put an attribute with a
+     * <code>null</code> value: the value may be <code>null</code>.
+     *
+     * @param attributeType the type of the new attribute to be put
+     * @param values the String values of the new attribute to be put
+     * @return the old attribute with the same identifier, if exists; otherwise
+     * <code>null</code>
+     * @throws NamingException if there are failures
      */
-    public ServerAttribute put( AttributeType attributeType, String... values ) throws NamingException
+    public EntryAttribute put( AttributeType attributeType, String... values ) throws NamingException
     {
         return put( null, attributeType, values );
     }
 
     
     /**
-     * Stores a new attribute with some String values into an entry, setting
-     * the User Provided ID in the same time.
-     *
-     * @param upId The User provided ID
-     * @param attributeType The associated AttributeType
-     * @param values The String values to store into the new Attribute
-     * @return The existing attribute if any
-     * @throws NamingException 
+     * <p>
+     * Places a new attribute with the supplied AttributeType and some values 
+     * into the attribute collection. 
+     * </p>
+     * <p>
+     * If there is already an attribute with the same AttributeType, the old
+     * one is removed from the collection and is returned by this method. 
+     * </p>
+     * <p>
+     * This method provides a mechanism to put an attribute with a
+     * <code>null</code> value: the value may be <code>null</code>.
+     *
+     * @param attributeType the type of the new attribute to be put
+     * @param values the values of the new attribute to be put
+     * @return the old attribute with the same identifier, if exists; otherwise
+     * <code>null</code>
+     * @throws NamingException if there are failures
      */
-    public ServerAttribute put( String upId, AttributeType attributeType, String... values ) throws NamingException
+    public EntryAttribute put( AttributeType attributeType, Value<?>... values ) throws NamingException
     {
-        upId = getUpId( upId, attributeType );
-        attributeType = getAttributeType( upId, attributeType );
-
-        ServerAttribute serverAttribute = new DefaultServerAttribute( upId, attributeType );
-
-        // We simply have to set the current attribute values
-        serverAttribute.put( values );
-        return serverAttributeMap.put( attributeType, serverAttribute );
+        return put( null, attributeType, values );
     }
 
 
     /**
-     * Stores a new attribute, creating it from its attributeType and byte[] values.
      * <p>
-     * The values are byte[], so the attributeType must be non-humanReadable.
-     * 
-     * @param attributeType The attributeType
-     * @param values The byte[] values to add to the attribute
-     * @return The existing ServerAttribute which has been replaced, if any
-     * @throws NamingException If some values conflict with the attributeType
+     * Places attributes in the attribute collection. 
+     * </p>
+     * <p>If there is already an attribute with the same ID as any of the 
+     * new attributes, the old ones are removed from the collection and 
+     * are returned by this method. If there was no attribute with the 
+     * same ID the return value is <code>null</code>.
+     *</p>
+     *
+     * @param attributes the attributes to be put
+     * @return the old attributes with the same OID, if exist; otherwise
+     *         <code>null</code>
+     * @exception NamingException if the operation fails
      */
-    public ServerAttribute put( AttributeType attributeType, byte[]... values ) throws NamingException
+    public List<EntryAttribute> put( EntryAttribute... attributes ) throws NamingException
     {
-        return put( null, attributeType, values );
+        List<EntryAttribute> previous = new ArrayList<EntryAttribute>();
+        
+        for ( EntryAttribute serverAttribute:attributes )
+        {
+            if ( serverAttribute == null )
+            {
+                String message = "The ServerAttribute list should not contain null elements";
+                LOG.error( message );
+                throw new IllegalArgumentException( message );
+            }
+            
+            EntryAttribute removed = this.attributes.put( ((ServerAttribute)serverAttribute).getAttributeType(), serverAttribute );
+            
+            if ( removed != null )
+            {
+                previous.add( removed );
+            }
+        }
+        
+        return previous;
     }
 
 
     /**
-     * Store a new attribute with some String values into an entry, setting
-     * the User Provided ID in the same time.
-     *
-     * @param upId The User provided ID
-     * @param attributeType The associated AttributeType
-     * @param values The byte[] values to store into the new Attribute
-     * @return The existing attribute if any
-     * @throws NamingException 
+     * <p>
+     * Places a new attribute with the supplied AttributeType and some binary values 
+     * into the attribute collection. 
+     * </p>
+     * <p>
+     * The given User provided ID will be used for this new AttributeEntry.
+     * </p>
+     * <p>
+     * If there is already an attribute with the same AttributeType, the old
+     * one is removed from the collection and is returned by this method. 
+     * </p>
+     * <p>
+     * This method provides a mechanism to put an attribute with a
+     * <code>null</code> value: the value may be <code>null</code>.
+     *
+     * @param upId The User Provided ID to be stored into the AttributeEntry
+     * @param attributeType the type of the new attribute to be put
+     * @param values the binary values of the new attribute to be put
+     * @return the old attribute with the same identifier, if exists; otherwise
+     * <code>null</code>
+     * @throws NamingException if there are failures.
      */
-    public ServerAttribute put( String upId, AttributeType attributeType, byte[]... values ) throws NamingException
+    public EntryAttribute put( String upId, AttributeType attributeType, byte[]... values ) throws NamingException
     {
         if ( attributeType == null )
         {
@@ -703,651 +1331,829 @@
             LOG.error( message );
             throw new IllegalArgumentException( message );
         }
-        
-        upId = getUpId( upId, attributeType );
-        attributeType = getAttributeType( upId, attributeType );
 
+        if ( !StringTools.isEmpty( upId ) )
+        {
+            AttributeType tempAT = getAttributeType( upId );
+        
+            if ( !tempAT.equals( attributeType ) )
+            {
+                String message = "The '" + upId + "' id is not compatible with the '" + attributeType + "' attribute type";
+                LOG.error( message );
+                throw new IllegalArgumentException( message );
+            }
+        }
+        else
+        {
+            upId = getUpId( upId, attributeType );
+        }
+        
         if ( attributeType.equals( OBJECT_CLASS_AT ) )
         {
             String message = "Only String values supported for objectClass attribute";
-            LOG.error(  message  );
+            LOG.error( message );
             throw new UnsupportedOperationException( message );
         }
 
-        ServerAttribute serverAttribute = new DefaultServerAttribute( upId, attributeType );
-        serverAttribute.put( values );
-        return serverAttributeMap.put( attributeType, serverAttribute );
+        EntryAttribute attribute = new DefaultServerAttribute( upId, attributeType, values );
+        return attributes.put( attributeType, attribute );
     }
 
 
-    public List<ServerAttribute> remove( AttributeType... attributeTypes ) throws NamingException
+    /**
+     * <p>
+     * Places a new attribute with the supplied AttributeType and some String values 
+     * into the attribute collection. 
+     * </p>
+     * <p>
+     * The given User provided ID will be used for this new AttributeEntry.
+     * </p>
+     * <p>
+     * If there is already an attribute with the same AttributeType, the old
+     * one is removed from the collection and is returned by this method. 
+     * </p>
+     * <p>
+     * This method provides a mechanism to put an attribute with a
+     * <code>null</code> value: the value may be <code>null</code>.
+     *
+     * @param upId The User Provided ID to be stored into the AttributeEntry
+     * @param attributeType the type of the new attribute to be put
+     * @param values the String values of the new attribute to be put
+     * @return the old attribute with the same identifier, if exists; otherwise
+     * <code>null</code>
+     * @throws NamingException if there are failures.
+     */
+    public EntryAttribute put( String upId, AttributeType attributeType, String... values ) throws NamingException
     {
-        if ( attributeTypes == null )
+        if ( attributeType == null )
         {
-            return null;
+            try
+            {
+                attributeType = getAttributeType( upId );
+            }
+            catch ( IllegalArgumentException iae )
+            {
+                String message = "The attributeType should not be null";
+                LOG.error( message );
+                throw new IllegalArgumentException( message );
+            }
         }
-        
-        List<ServerAttribute> attributes = new ArrayList<ServerAttribute>( attributeTypes.length );
-        
-        for ( AttributeType attributeType:attributeTypes )
+        else
         {
-            if ( serverAttributeMap.containsKey( attributeType ) )
+            if ( !StringTools.isEmpty( upId ) )
             {
-                attributes.add( serverAttributeMap.remove( attributeType ) );
+                AttributeType tempAT = getAttributeType( upId );
+            
+                if ( !tempAT.equals( attributeType ) )
+                {
+                    String message = "The '" + upId + "' id is not compatible with the '" + attributeType + "' attribute type";
+                    LOG.error( message );
+                    throw new IllegalArgumentException( message );
+                }
+            }
+            else
+            {
+                upId = getUpId( upId, attributeType );
             }
         }
         
-        return attributes;
+        EntryAttribute attribute = new DefaultServerAttribute( upId, attributeType, values );
+        return attributes.put( attributeType, attribute );
     }
 
 
-    public List<ServerAttribute> remove( String... upIds ) throws NamingException
+    /**
+     * <p>
+     * Places a new attribute with the supplied AttributeType and some values 
+     * into the attribute collection. 
+     * </p>
+     * <p>
+     * The given User provided ID will be used for this new AttributeEntry.
+     * </p>
+     * <p>
+     * If there is already an attribute with the same AttributeType, the old
+     * one is removed from the collection and is returned by this method. 
+     * </p>
+     * <p>
+     * This method provides a mechanism to put an attribute with a
+     * <code>null</code> value: the value may be <code>null</code>.
+     *
+     * @param upId The User Provided ID to be stored into the AttributeEntry
+     * @param attributeType the type of the new attribute to be put
+     * @param values the values of the new attribute to be put
+     * @return the old attribute with the same identifier, if exists; otherwise
+     * <code>null</code>
+     * @throws NamingException if there are failures.
+     */
+    public EntryAttribute put( String upId, AttributeType attributeType, Value<?>... values ) throws NamingException
     {
-        assert registries != null : "The AttributeType registry should not be null";
-
-        if ( upIds == null )
+        if ( attributeType == null )
         {
-            return null;
+            String message = "The attributeType should not be null";
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
         }
+
+        if ( !StringTools.isEmpty( upId ) )
+        {
+            AttributeType tempAT = getAttributeType( upId );
         
-        List<ServerAttribute> attributes = new ArrayList<ServerAttribute>( upIds.length );
-        
-        for ( String upId:upIds )
+            if ( !tempAT.equals( attributeType ) )
+            {
+                String message = "The '" + upId + "' id is not compatible with the '" + attributeType + "' attribute type";
+                LOG.error( message );
+                throw new IllegalArgumentException( message );
+            }
+        }
+        else
         {
-            AttributeType attributeType = registries.getAttributeTypeRegistry().lookup( upId );
-    
-            attributes.add( serverAttributeMap.remove( attributeType ) );
+            upId = getUpId( upId, attributeType );
         }
         
-        return attributes;
-    }
-
-
-    public void clear()
-    {
-        serverAttributeMap.clear();
-
-        //setObjectClassAttribute( new ObjectClassAttribute( registries ) );
-    }
-
-
-    public LdapDN getDn()
-    {
-        return dn;
-    }
-
-
-    public void setDn( LdapDN dn )
-    {
-        this.dn = dn;
-    }
-
-
-    public Iterator<ServerAttribute> iterator()
-    {
-        return Collections.unmodifiableMap( serverAttributeMap ).values().iterator();
+        EntryAttribute attribute = new DefaultServerAttribute( upId, attributeType, values );
+        return attributes.put( attributeType, attribute );
     }
 
 
-    public int size()
-    {
-        return serverAttributeMap.size();
-    }
-    
-    
     /**
-     * Clone an entry. All the element are duplicated, so a modification on
-     * the original object won't affect the cloned object, as a modification
-     * on the cloned object has no impact on the original object
+     * <p>
+     * Put an attribute (represented by its ID and some binary values) into an entry. 
+     * </p>
+     * <p> 
+     * If the attribute already exists, the previous attribute will be 
+     * replaced and returned.
+     * </p>
+     * <p>
+     * If the upId is not the ID of an existing AttributeType, an IllegalArgumentException is thrown.
+     * </p>
+     *
+     * @param upId The attribute ID
+     * @param values The list of binary values to put. It can be empty.
+     * @return The replaced attribute
      */
-    public ServerEntry clone()
+    public EntryAttribute put( String upId, byte[]... values )
     {
         try
         {
-            // First, clone the structure
-            DefaultServerEntry clone = (DefaultServerEntry)super.clone();
-            
-            // A serverEntry has a DN, an ObjectClass attribute
-            // and many attributes
-            // Clone the DN
-            clone.dn = (LdapDN)dn.clone();
-            
-            // clone the ServerAttribute Map
-            clone.serverAttributeMap = (Map<AttributeType, ServerAttribute>)(((HashMap<AttributeType, ServerAttribute>)serverAttributeMap).clone());
-            
-            // now clone all the servrAttributes
-            clone.serverAttributeMap.clear();
-            
-            for ( AttributeType key:serverAttributeMap.keySet() )
-            {
-                ServerAttribute value = (ServerAttribute)serverAttributeMap.get( key ).clone();
-                clone.serverAttributeMap.put( key, value );
-            }
-            
-            // We are done !
-            return clone;
+            return put( upId, getAttributeType( upId ), values );
         }
-        catch ( CloneNotSupportedException cnse )
+        catch ( NamingException ne )
         {
-            return null;
+            String message = "Error while adding values into the '" + upId + "' attribute. Error : " + 
+                ne.getMessage();
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
         }
     }
-    
+
 
     /**
-     * Checks if an entry contains an attribute with a given value.
+     * <p>
+     * Put an attribute (represented by its ID and some String values) into an entry. 
+     * </p>
+     * <p> 
+     * If the attribute already exists, the previous attribute will be 
+     * replaced and returned.
+     * </p>
+     * <p>
+     * If the upId is not the ID of an existing AttributeType, an IllegalArgumentException is thrown.
+     * </p>
      *
-     * @param attributeType The Attributetype we are looking for
-     * @param value The searched value
-     * @return <code>true</code> if the value is found within the attribute
-     * @throws NamingException If there is a problem
+     * @param upId The attribute ID
+     * @param values The list of String values to put. It can be empty.
+     * @return The replaced attribute
      */
-    public boolean contains( AttributeType attributeType, Value<?> value ) throws NamingException
-    {
-        if ( attributeType == null )
-        {
-            return false;
-        }
-        
-        if ( serverAttributeMap.containsKey( attributeType ) )
+    public EntryAttribute put( String upId, String... values )
+    {            
+
+        try
         {
-            return serverAttributeMap.get( attributeType ).contains( (Value<?>)value );
+            return put( upId, getAttributeType( upId ), values );
         }
-        else
+        catch ( NamingException ne )
         {
-            return false;
+            String message = "Error while adding values into the '" + upId + "' attribute. Error : " + 
+                ne.getMessage();
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
         }
     }
-    
-    
+
+
     /**
-     * Checks if an entry contains an attribute with a given value.
+     * <p>
+     * Put an attribute (represented by its ID and some values) into an entry. 
+     * </p>
+     * <p> 
+     * If the attribute already exists, the previous attribute will be 
+     * replaced and returned.
+     * </p>
+     * <p>
+     * If the upId is not the ID of an existing AttributeType, an IllegalArgumentException is thrown.
+     * </p>
      *
-     * @param id The Attribute we are looking for
-     * @param value The searched value
-     * @return <code>true</code> if the value is found within the attribute
-     * @throws NamingException If the attribute does not exists
+     * @param upId The attribute ID
+     * @param values The list of values to put. It can be empty.
+     * @return The replaced attribute
      */
-    public boolean contains( String id, Value<?> value ) throws NamingException
+    public EntryAttribute put( String upId, Value<?>... values )
     {
-        if ( id == null )
+        try
         {
-            return false;
+            return put( upId, getAttributeType( upId ), values );
         }
-        
-        AttributeType attributeType = registries.getAttributeTypeRegistry().lookup( id );
-        
-        if ( attributeType == null )
+        catch ( NamingException ne )
         {
-            return false;
+            String message = "Error while adding values into the '" + upId + "' attribute. Error : " + 
+                ne.getMessage();
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
         }
-        else if ( serverAttributeMap.containsKey( attributeType ) )
+    }
+
+
+    /**
+     * <p>
+     * Removes the specified binary values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns 
+     * <code>false</code>
+     * </p> 
+     *
+     * @param attributeType The attribute type  
+     * @param values the values to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist. 
+     */
+    public boolean remove( AttributeType attributeType, byte[]... values ) throws NamingException
+    {
+        try
         {
-            return serverAttributeMap.get( attributeType ).contains( (Value<?>)value );
+            EntryAttribute attribute = attributes.get( attributeType );
+            
+            if ( attribute == null )
+            {
+                // Can't remove values from a not existing attribute !
+                return false;
+            }
+            
+            int nbOldValues = attribute.size();
+            
+            // Remove the values
+            attribute.remove( values );
+            
+            if ( attribute.size() == 0 )
+            {
+                // No mare values, remove the attribute
+                attributes.remove( attributeType );
+                
+                return true;
+            }
+            
+            if ( nbOldValues != attribute.size() )
+            {
+                // At least one value have been removed, return true.
+                return true;
+            }
+            else
+            {
+                // No values have been removed, return false.
+                return false;
+            }
         }
-        else
+        catch ( IllegalArgumentException iae )
         {
+            LOG.error( "The removal of values for the missing '{}' attribute is not possible", attributeType );
             return false;
         }
     }
     
     
     /**
-     * Checks if an entry contains an attribute with a given value.
-     *
-     * @param id The Attribute we are looking for
-     * @param value The searched value
-     * @return <code>true</code> if the value is found within the attribute
-     * @throws NamingException If the attribute does not exists
+     * <p>
+     * Removes the specified String values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns 
+     * <code>false</code>
+     * </p> 
+     *
+     * @param attributeType The attribute type  
+     * @param values the values to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist. 
      */
-    public boolean contains( String id, String value ) throws NamingException
+    public boolean remove( AttributeType attributeType, String... values ) throws NamingException
     {
-        if ( id == null )
-        {
-            return false;
-        }
-        
-        AttributeType attributeType = registries.getAttributeTypeRegistry().lookup( id );
-        
-        if ( attributeType == null )
-        {
-            return false;
-        }
-        else if ( serverAttributeMap.containsKey( attributeType ) )
+        try
         {
-            return serverAttributeMap.get( attributeType ).contains( value );
+            EntryAttribute attribute = attributes.get( attributeType );
+            
+            if ( attribute == null )
+            {
+                // Can't remove values from a not existing attribute !
+                return false;
+            }
+            
+            int nbOldValues = attribute.size();
+            
+            // Remove the values
+            attribute.remove( values );
+            
+            if ( attribute.size() == 0 )
+            {
+                // No mare values, remove the attribute
+                attributes.remove( attributeType );
+                
+                return true;
+            }
+            
+            if ( nbOldValues != attribute.size() )
+            {
+                // At least one value have been removed, return true.
+                return true;
+            }
+            else
+            {
+                // No values have been removed, return false.
+                return false;
+            }
         }
-        else
+        catch ( IllegalArgumentException iae )
         {
+            LOG.error( "The removal of values for the missing '{}' attribute is not possible", attributeType );
             return false;
         }
     }
     
     
     /**
-     * Checks if an entry contains an attribute with a given value.
-     *
-     * @param attributeType The Attribute we are looking for
-     * @param value The searched value
-     * @return <code>true</code> if the value is found within the attribute
-     * @throws NamingException If the attribute does not exists
+     * <p>
+     * Removes the specified values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns 
+     * <code>false</code>
+     * </p> 
+     *
+     * @param attributeType The attribute type  
+     * @param values the values to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist. 
      */
-    public boolean contains( AttributeType attributeType, String value ) throws NamingException
+    public boolean remove( AttributeType attributeType, Value<?>... values ) throws NamingException
     {
-        if ( attributeType == null )
-        {
-            return false;
-        }
-        else if ( serverAttributeMap.containsKey( attributeType ) )
+        try
         {
-            return serverAttributeMap.get( attributeType ).contains( value );
+            EntryAttribute attribute = attributes.get( attributeType );
+            
+            if ( attribute == null )
+            {
+                // Can't remove values from a not existing attribute !
+                return false;
+            }
+            
+            int nbOldValues = attribute.size();
+            
+            // Remove the values
+            attribute.remove( values );
+            
+            if ( attribute.size() == 0 )
+            {
+                // No mare values, remove the attribute
+                attributes.remove( attributeType );
+                
+                return true;
+            }
+            
+            if ( nbOldValues != attribute.size() )
+            {
+                // At least one value have been removed, return true.
+                return true;
+            }
+            else
+            {
+                // No values have been removed, return false.
+                return false;
+            }
         }
-        else
+        catch ( IllegalArgumentException iae )
         {
+            LOG.error( "The removal of values for the missing '{}' attribute is not possible", attributeType );
             return false;
         }
     }
     
     
-    /**
-     * Checks if an entry contains an attribute with a given value.
-     *
-     * @param id The Attribute we are looking for
-     * @param value The searched value
-     * @return <code>true</code> if the value is found within the attribute
-     * @throws NamingException If the attribute does not exists
-     */
-    public boolean contains( String id, byte[] value ) throws NamingException
+    public List<EntryAttribute> remove( EntryAttribute... attributes ) throws NamingException
     {
-        if ( id == null )
+        List<EntryAttribute> removedAttributes = new ArrayList<EntryAttribute>();
+        
+        for ( EntryAttribute serverAttribute:attributes )
         {
-            return false;
+            if ( this.attributes.containsKey( ((ServerAttribute)serverAttribute).getAttributeType() ) )
+            {
+                this.attributes.remove( ((ServerAttribute)serverAttribute).getAttributeType() );
+                removedAttributes.add( serverAttribute );
+            }
         }
         
-        AttributeType attributeType = registries.getAttributeTypeRegistry().lookup( id );
-        
-        if ( attributeType == null )
+        return removedAttributes;
+    }
+
+
+    /**
+     * <p>
+     * Removes the specified binary values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns 
+     * <code>false</code>
+     * </p> 
+     *
+     * @param upId The attribute ID 
+     * @param values the values to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist. 
+     */
+    public boolean remove( String upId, byte[]... values ) throws NamingException
+    {
+        try
         {
-            return false;
+            AttributeType attributeType = getAttributeType( upId );
+
+            return remove( attributeType, values );
         }
-        else if ( serverAttributeMap.containsKey( attributeType ) )
+        catch ( NamingException ne )
         {
-            return serverAttributeMap.get( attributeType ).contains( value );
+            LOG.error( "The removal of values for the missing '{}' attribute is not possible", upId );
+            return false;
         }
-        else
+        catch ( IllegalArgumentException iae )
         {
+            LOG.error( "The removal of values for the bad '{}' attribute is not possible", upId );
             return false;
         }
     }
     
     
     /**
-     * Checks if an entry contains an attribute with a given value.
-     *
-     * @param attributeType The Attribute we are looking for
-     * @param value The searched value
-     * @return <code>true</code> if the value is found within the attribute
-     * @throws NamingException If the attribute does not exists
+     * <p>
+     * Removes the specified String values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns 
+     * <code>false</code>
+     * </p> 
+     *
+     * @param upId The attribute ID 
+     * @param values the values to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist. 
      */
-    public boolean contains( AttributeType attributeType, byte[] value ) throws NamingException
+    public boolean remove( String upId, String... values ) throws NamingException
     {
-        if ( attributeType == null )
+        try
         {
-            return false;
+            AttributeType attributeType = getAttributeType( upId );
+
+            return remove( attributeType, values );
         }
-        else if ( serverAttributeMap.containsKey( attributeType ) )
+        catch ( NamingException ne )
         {
-            return serverAttributeMap.get( attributeType ).contains( value );
+            LOG.error( "The removal of values for the missing '{}' attribute is not possible", upId );
+            return false;
         }
-        else
+        catch ( IllegalArgumentException iae )
         {
+            LOG.error( "The removal of values for the bad '{}' attribute is not possible", upId );
             return false;
         }
     }
     
     
     /**
-     * Gets all the attributes type (ObjectClasses, May and Must)
-     *
-     * @return The combined set of all the attributes, including ObjectClass.
-     */
-    public Set<AttributeType> getAttributeTypes()
-    {
-        return serverAttributeMap.keySet();
-    }
-    
-    
-    /**
-     * Add a new ServerAttribute, with its upId. If the upId is null,
-     * default to the AttributeType name.
-     * 
-     * Updates the serverAttributeMap.
-     */
-    private void createAttribute( String upId, AttributeType attributeType, Value<?>... values ) throws NamingException, InvalidAttributeValueException
-    {
-        ServerAttribute attribute = new DefaultServerAttribute( attributeType, values );
-        attribute.setUpId( upId, attributeType );
-        serverAttributeMap.put( attributeType, attribute );
-    }
-    
-    
-    /**
-     * Add a new ServerAttribute, with its upId. If the upId is null,
-     * default to the AttributeType name.
-     * 
-     * Updates the serverAttributeMap.
-     */
-    private void createAttribute( String upId, AttributeType attributeType, String... values ) throws NamingException, InvalidAttributeValueException
-    {
-        ServerAttribute attribute = new DefaultServerAttribute( attributeType, values );
-        attribute.setUpId( upId, attributeType );
-        serverAttributeMap.put( attributeType, attribute );
-    }
-    
-    
-    /**
-     * Add a new ServerAttribute, with its upId. If the upId is null,
-     * default to the AttributeType name.
-     * 
-     * Updates the serverAttributeMap.
-     */
-    private void createAttribute( String upId, AttributeType attributeType, byte[]... values ) throws NamingException, InvalidAttributeValueException
-    {
-        ServerAttribute attribute = new DefaultServerAttribute( attributeType, values );
-        attribute.setUpId( upId, attributeType );
-        serverAttributeMap.put( attributeType, attribute );
-    }
-    
-    
-    /*-------------------------------------------------------------------------
-     *
-     * Add an attribute into this entry. We have many different cases.
-     * 1) We are adding a value to an ObjectClass or an ObjectClass to the
-     * entry
-     * 2) We are adding an attribute or a value to an attribute which is not 
-     * an ObjectClass
-     * 
-     * For (1), we will have to check :
-     *  - that the value is not binary
-     *  - we won't add an existing objectClass
-     *  - and the ObjectClass must be valid
-     *  
-     * If everything is fine, we will proceed accordingly to the existence
-     * of the ObjectClass attribute :
-     *  - if the ObjectClass attribute has already been created, we will 
-     *  create the ObjectClass, set its value and add an Attribute into 
-     *  the values Map
-     *  - otherwise, we will just add the value to the Values Map 
-     *  
-     * For (2), we just have to update the values Map :
-     *  - if the attribute already exists, we add the value (no duplicate)
-     *  - or we just add a new attribute to the Map
-     *-----------------------------------------------------------------------*/
-    /**
-     * Add an attribute (represented by its ID and some String values) into an 
-     * entry.
-     * <p> 
-     * If we already have an attribute with the same value, nothing is done
-     *
-     * @param attributeType The attribute Type
-     * @param values The list of String values to inject. It can be empty
-     * @throws NamingException If the attribute does not exist
+     * <p>
+     * Removes the specified Value values from an attribute.
+     * </p>
+     * <p>
+     * If at least one value is removed, this method returns <code>true</code>.
+     * </p>
+     * <p>
+     * If there is no more value after having removed the values, the attribute
+     * will be removed too.
+     * </p>
+     * <p>
+     * If the attribute does not exist, nothing is done and the method returns 
+     * <code>false</code>
+     * </p> 
+     *
+     * @param upId The attribute ID 
+     * @param values the values to be removed
+     * @return <code>true</code> if at least a value is removed, <code>false</code>
+     * if not all the values have been removed or if the attribute does not exist. 
      */
-    public void add( AttributeType attributeType, String... values ) throws NamingException
+    public boolean remove( String upId, Value<?>... values ) throws NamingException
     {
-        if ( attributeType == null )
+        try
         {
-            String message = "The attributeType should not be null";
-            LOG.error( message );
-            throw new IllegalArgumentException( message );
+            AttributeType attributeType = getAttributeType( upId );
+
+            return remove( attributeType, values );
         }
-        
-        ServerAttribute attribute = serverAttributeMap.get( attributeType );
-        
-        if ( attribute != null )
+        catch ( NamingException ne )
         {
-            // This Attribute already exist, we add the values 
-            // into it
-            attribute.add( values );
+            LOG.error( "The removal of values for the missing '{}' attribute is not possible", upId );
+            return false;
         }
-        else
+        catch ( IllegalArgumentException iae )
         {
-            // We have to create a new Attribute and set the values
-            // and the upId
-            createAttribute( null, attributeType, values );
+            LOG.error( "The removal of values for the bad '{}' attribute is not possible", upId );
+            return false;
         }
     }
-
+    
     
     /**
-     * Add an attribute (represented by its ID and some Binary values) into an 
-     * entry.
-     * <p> 
-     * If we already have an attribute with the same value, nothing is done
+     * <p>
+     * Removes the attribute with the specified AttributeTypes. 
+     * </p>
+     * <p>
+     * The removed attribute are returned by this method. 
+     * </p>
+     * <p>
+     * If there is no attribute with the specified AttributeTypes,
+     * the return value is <code>null</code>.
+     * </p>
      *
-     * @param attributeType The attribute Type
-     * @param values The list of binary values to inject. It can be empty
-     * @throws NamingException If the attribute does not exist
+     * @param attributes the AttributeTypes to be removed
+     * @return the removed attributes, if any, as a list; otherwise <code>null</code>
      */
-    public void add( AttributeType attributeType, byte[]... values ) throws NamingException

[... 556 lines stripped ...]