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/08/15 01:12:13 UTC

svn commit: r686082 [1/7] - in /directory: apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ apacheds/branches/bigbang/core-entry/src/test/java/org/apache/directory/server/core/entry/ apacheds/branches/bigbang/c...

Author: elecharny
Date: Thu Aug 14 16:12:09 2008
New Revision: 686082

URL: http://svn.apache.org/viewvc?rev=686082&view=rev
Log:
o Replaced some of the ServerUtils methods by direct calls to the equivalent methods in the Server Entry/Attribute/Modification classes
o Completely reviewed the serialization of entries/attributes/values/Modifications/LdifEnties
o Added tests for all those serialization
o Used Externalizable,instead of Serializable
o Added some missing Javadoc
o Fixed some failing tests in ModifyDN class
o Fixed the wrong LDIF in referrals tests
o Removed a lot of references on Attribute(s) and JNDI objects
o Removed the password wrom the LdapPrincipal serialized form

Added:
    directory/apacheds/branches/bigbang/core/src/test/java/org/apache/directory/server/core/authn/LdapPrincipalTest.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/ClientModification.java
    directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/entry/client/ClientModificationTest.java
Modified:
    directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ClonedServerEntry.java
    directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerAttribute.java
    directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerEntry.java
    directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ServerAttribute.java
    directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ServerBinaryValue.java
    directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ServerEntry.java
    directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ServerEntrySerializer.java
    directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ServerEntryUtils.java
    directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ServerModification.java
    directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ServerStringValue.java
    directory/apacheds/branches/bigbang/core-entry/src/test/java/org/apache/directory/server/core/entry/DefaultServerAttributeTest.java
    directory/apacheds/branches/bigbang/core-entry/src/test/java/org/apache/directory/server/core/entry/DefaultServerEntryTest.java
    directory/apacheds/branches/bigbang/core-entry/src/test/java/org/apache/directory/server/core/entry/ServerBinaryValueTest.java
    directory/apacheds/branches/bigbang/core-entry/src/test/java/org/apache/directory/server/core/entry/ServerEntrySerializerTest.java
    directory/apacheds/branches/bigbang/core-entry/src/test/java/org/apache/directory/server/core/entry/ServerModificationTest.java
    directory/apacheds/branches/bigbang/core-entry/src/test/java/org/apache/directory/server/core/entry/ServerStringValueTest.java
    directory/apacheds/branches/bigbang/core-integ/src/main/java/org/apache/directory/server/core/integ/IntegrationUtils.java
    directory/apacheds/branches/bigbang/core-integ/src/main/java/org/apache/directory/server/core/integ/state/AbstractState.java
    directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/authn/SimpleAuthenticationIT.java
    directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/authz/AuthorizationServiceAsNonAdminIT.java
    directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/jndi/ListIT.java
    directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/jndi/ModifyContextIT.java
    directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/jndi/ObjStateFactoryIT.java
    directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/jndi/ReferralIT.java
    directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/operational/OperationalAttributeServiceIT.java
    directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/schema/SchemaPersistenceIT.java
    directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/schema/SchemaServiceIT.java
    directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/schema/SubschemaSubentryIT.java
    directory/apacheds/branches/bigbang/core-jndi/src/main/java/org/apache/directory/server/core/jndi/ServerDirContext.java
    directory/apacheds/branches/bigbang/core-unit/src/main/java/org/apache/directory/server/core/unit/AbstractTestCase.java
    directory/apacheds/branches/bigbang/core-unit/src/main/java/org/apache/directory/server/core/unit/IntegrationUtils.java
    directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/DefaultCoreSession.java
    directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/DefaultDirectoryService.java
    directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/authn/LdapPrincipal.java
    directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/authz/AciAuthorizationInterceptor.java
    directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogEvent.java
    directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogInterceptor.java
    directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/changelog/DefaultChangeLog.java
    directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/changelog/MemoryChangeLogStore.java
    directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/collective/CollectiveAttributesSchemaChecker.java
    directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/interceptor/InterceptorChain.java
    directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/interceptor/context/ModifyOperationContext.java
    directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/partition/impl/btree/gui/PartitionFrame.java
    directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmPartition.java
    directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/schema/SchemaInterceptor.java
    directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/sp/StoredProcExecutionManager.java
    directory/apacheds/branches/bigbang/core/src/test/java/org/apache/directory/server/core/changelog/MemoryChangeLogStoreTest.java
    directory/apacheds/branches/bigbang/protocol-shared/src/main/java/org/apache/directory/server/protocol/shared/store/LdifFileLoader.java
    directory/apacheds/branches/bigbang/protocol-shared/src/main/java/org/apache/directory/server/protocol/shared/store/LdifLoadFilter.java
    directory/apacheds/branches/bigbang/server-integ/src/main/java/org/apache/directory/server/integ/state/AbstractState.java
    directory/apacheds/branches/bigbang/server-integ/src/test/java/org/apache/directory/server/operations/bind/BindIT.java
    directory/apacheds/branches/bigbang/server-integ/src/test/java/org/apache/directory/server/operations/bind/SimpleBindIT.java
    directory/apacheds/branches/bigbang/server-integ/src/test/java/org/apache/directory/server/operations/modifydn/ModifyRdnIT.java
    directory/apacheds/branches/bigbang/server-integ/src/test/java/org/apache/directory/server/operations/search/ReferralSearchIT.java
    directory/apacheds/branches/bigbang/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchIT.java
    directory/apacheds/branches/bigbang/server-jndi/src/main/java/org/apache/directory/server/configuration/ApacheDS.java
    directory/apacheds/branches/bigbang/server-jndi/src/test/java/org/apache/directory/server/configuration/ApacheDSTest.java
    directory/apacheds/branches/bigbang/server-tools/src/main/java/org/apache/directory/server/tools/ImportCommand.java
    directory/apacheds/branches/bigbang/server-unit/src/main/java/org/apache/directory/server/unit/AbstractServerTest.java
    directory/shared/branches/bigbang/convert/src/main/java/org/apache/directory/shared/converter/schema/AttributeTypeHolder.java
    directory/shared/branches/bigbang/convert/src/main/java/org/apache/directory/shared/converter/schema/ObjectClassHolder.java
    directory/shared/branches/bigbang/convert/src/main/java/org/apache/directory/shared/converter/schema/SchemaElementImpl.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/Entry.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/EntryAttribute.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/Modification.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/ModificationOperation.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/ClientBinaryValue.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/ClientStringValue.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/DefaultClientAttribute.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/DefaultClientEntry.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/ldif/LdifEntry.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/ldif/LdifReader.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/ldif/LdifUtils.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/name/LdapDN.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/name/Rdn.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/schema/SchemaUtils.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/util/AttributeUtils.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/util/DNUtils.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/util/Position.java
    directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/util/PropertiesUtils.java
    directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/entry/client/ClientBinaryValueTest.java
    directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/entry/client/ClientStringValueTest.java
    directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/entry/client/DefaultClientAttributeTest.java
    directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/entry/client/DefaultClientEntryTest.java
    directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/ldif/LdifReaderTest.java
    directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/ldif/LdifUtilsTest.java
    directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/name/AttributeTypeAndValueTest.java
    directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/name/RdnTest.java
    directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/util/AttributeUtilsTest.java

Modified: directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ClonedServerEntry.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ClonedServerEntry.java?rev=686082&r1=686081&r2=686082&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ClonedServerEntry.java (original)
+++ directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ClonedServerEntry.java Thu Aug 14 16:12:09 2008
@@ -20,6 +20,9 @@
 package org.apache.directory.server.core.entry;
 
 
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
@@ -27,8 +30,10 @@
 
 import javax.naming.NamingException;
 
+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.entry.client.DefaultClientEntry;
 import org.apache.directory.shared.ldap.name.LdapDN;
 import org.apache.directory.shared.ldap.schema.AttributeType;
 
@@ -75,7 +80,7 @@
     /**
      * @return the cloned Entry
      */
-    public ServerEntry getClonedEntry()
+    public Entry getClonedEntry()
     {
         return clonedEntry;
     }
@@ -399,6 +404,44 @@
     }
 
 
+    public Entry toClientEntry() throws NamingException
+    {
+        // Copy the DN
+        Entry clientEntry = new DefaultClientEntry( clonedEntry.getDn() );
+        
+        // Convert each attribute 
+        for ( EntryAttribute clonedEntry:this )
+        {
+            EntryAttribute clientAttribute = ((ServerAttribute)clonedEntry).toClientAttribute();
+            clientEntry.add( clientAttribute );
+        }
+        
+        return clientEntry;
+    }
+    
+    
+    /**
+     * @see java.io.Externalizable#readExternal(ObjectInput)
+     * 
+     * We can't use this method for a ServerEntry
+     */
+    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        throw new IllegalStateException( "Cannot use standard serialization for a ServerAttribute" );
+    }
+    
+    
+    /**
+     * @see java.io.Externalizable#writeExternal(ObjectOutput)
+     * 
+     * We can't use this method for a ServerEntry
+     */
+    public void writeExternal( ObjectOutput out ) throws IOException
+    {
+        throw new IllegalStateException( "Cannot use standard serialization for a ServerEntry" );
+    }
+    
+    
     public ServerEntry clone()
     {
         return ( ServerEntry ) clonedEntry.clone();
@@ -676,9 +719,36 @@
             return 0;
         }
     
+        
         public ServerEntry clone()
         {
             return new EmptyEntry( dn );
         }
+
+        
+        public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+        {
+        }
+        
+        
+        public void writeExternal( ObjectOutput out ) throws IOException
+        {
+        }
+        
+        
+        public Entry toClientEntry() throws NamingException
+        {
+            // Copy the DN
+            Entry clientEntry = new DefaultClientEntry( dn );
+            
+            // Convert each attribute 
+            for ( EntryAttribute serverAttribute:this )
+            {
+                EntryAttribute clientAttribute = ((ServerAttribute)serverAttribute).toClientAttribute();
+                clientEntry.add( clientAttribute );
+            }
+            
+            return clientEntry;
+        }
     }
 }

Modified: directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerAttribute.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerAttribute.java?rev=686082&r1=686081&r2=686082&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerAttribute.java (original)
+++ directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerAttribute.java Thu Aug 14 16:12:09 2008
@@ -19,6 +19,10 @@
 package org.apache.directory.server.core.entry;
 
 
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
 import javax.naming.NamingException;
 import javax.naming.directory.InvalidAttributeValueException;
 
@@ -42,6 +46,8 @@
  */
 public final class DefaultServerAttribute extends DefaultClientAttribute implements ServerAttribute
 {
+    public static final long serialVersionUID = 1L;
+    
     /** logger for reporting errors that might not be handled properly upstream */
     private static final Logger LOG = LoggerFactory.getLogger( DefaultServerAttribute.class );
     
@@ -49,9 +55,9 @@
     private AttributeType attributeType;
     
     
-    // -----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
     // utility methods
-    // -----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
     /**
      * Private helper method used to set an UpId from an attributeType
      * 
@@ -71,381 +77,157 @@
     }
     
     
+    //-------------------------------------------------------------------------
+    // Constructors
+    //-------------------------------------------------------------------------
     /**
-     * <p>
-     * Check if the current attribute type is of the expected attributeType
-     * </p>
-     * <p>
-     * This method won't tell if the current attribute is a descendant of 
-     * the attributeType. For instance, the "CN" serverAttribute will return
-     * false if we ask if it's an instance of "Name". 
-     * </p> 
+     * 
+     * Creates a new instance of DefaultServerAttribute, by copying
+     * another attribute, which can be a ClientAttribute. If the other
+     * attribute is a ServerAttribute, it will be copied.
      *
-     * @param attributeId The AttributeType ID to check
-     * @return True if the current attribute is of the expected attributeType
-     * @throws InvalidAttributeValueException If there is no AttributeType
+     * @param attributeType The attribute's type 
+     * @param attribute The attribute to be copied
      */
-    public boolean instanceOf( String attributeId ) throws InvalidAttributeValueException
+    public DefaultServerAttribute( AttributeType attributeType, EntryAttribute attribute )
     {
-        String trimmedId = StringTools.trim( attributeId );
-        
-        if ( StringTools.isEmpty( trimmedId ) )
-        {
-            return false;
-        }
-        
-        String normId = StringTools.lowerCaseAscii( trimmedId );
-        
-        for ( String name:attributeType.getNamesRef() )
+        // Copy the common values. isHR is only available on a ServerAttribute 
+        this.attributeType = attributeType;
+        this.id = attribute.getId();
+        this.upId = attribute.getUpId();
+
+        if ( attribute instanceof ServerAttribute )
         {
-            if ( normId.equalsIgnoreCase( name ) )
+            isHR = attribute.isHR();
+
+            // Copy all the values
+            for ( Value<?> value:attribute )
             {
-                return true;
+                add( value.clone() );
             }
         }
-        
-        return normId.equalsIgnoreCase( attributeType.getOid() );
-    }
-    
-
-    /**
-     * <p>
-     * Overload the {@link DefaultClientAttribute#setId(String)} method.
-     * </p>
-     * <p>
-     * As the attributeType has already been set, we have to be sure that the 
-     * argument is compatible with the attributeType's name. 
-     * </p>
-     * <p>
-     * If the given ID is not compatible with the attributeType's possible
-     * names, the previously loaded ID will be kept.
-     * </p>
-     *
-     * @param id The attribute ID
-     */
-    public void setId( String id )
-    {
-        if ( !StringTools.isEmpty( StringTools.trim( id  ) ) )
+        else
         {
-            if ( attributeType.getName() == null )
+            
+            try
             {
-                // If the name is null, then we may have to store an OID
-                if ( OID.isOID( id )  && attributeType.getOid().equals( id ) )
-                {
-                    // Everything is fine, store the upId.
-                    // This should not happen...
-                    super.setId( id );
-                }
+                isHR = attributeType.getSyntax().isHumanReadable();
             }
-            else
+            catch ( NamingException ne )
             {
-                // We have at least one name. Check that the normalized upId
-                // is one of those names. Otherwise, the upId may be an OID too.
-                // In this case, it must be equals to the attributeType OID.
-                String normId = StringTools.lowerCaseAscii( StringTools.trim( id ) );
-                
-                for ( String atName:attributeType.getNamesRef() )
+                // Do nothing : the syntax should always exist ...
+            }
+            
+
+            // Copy all the values
+            for ( Value<?> clientValue:attribute )
+            {
+                Value<?> serverValue = null; 
+
+                // We have to convert the value first
+                if ( clientValue instanceof ClientStringValue )
                 {
-                    if ( atName.equalsIgnoreCase( normId ) )
+                    if ( isHR )
                     {
-                        // Found ! We can store the upId and get out
-                        super.setId( normId );
-                        return;
+                        serverValue = new ServerStringValue( attributeType, (String)clientValue.get() );
+                    }
+                    else
+                    {
+                        // We have to convert the value to a binary value first
+                        serverValue = new ServerBinaryValue( attributeType, 
+                            StringTools.getBytesUtf8( (String)clientValue.get() ) );
                     }
                 }
-                
-                // Last case, the UpId is an OID
-                if ( OID.isOID( normId ) && attributeType.getOid().equals( normId ) )
-                {
-                    // We have an OID : stores it
-                    super.setUpId( normId );
-                }
-                else
+                else if ( clientValue instanceof ClientBinaryValue )
                 {
-                    // The id is incorrect : this is not allowed 
-                    throw new IllegalArgumentException( "The ID '" + id + "'is incompatible with the AttributeType's id '" + 
-                        attributeType.getName() + "'" );
+                    if ( isHR )
+                    {
+                        // We have to convert the value to a String value first
+                        serverValue = new ServerStringValue( attributeType, 
+                            StringTools.utf8ToString( (byte[])clientValue.get() ) );
+                    }
+                    else
+                    {
+                        serverValue = new ServerBinaryValue( attributeType, (byte[])clientValue.get() );
+                    }
                 }
+
+                add( serverValue );
             }
         }
-        else
-        {
-            throw new IllegalArgumentException( "An ID cannnot be null, empty, or resolved to an emtpy" +
-            " value when trimmed" );
-        }
     }
     
     
+    // maybe have some additional convenience constructors which take
+    // an initial value as a string or a byte[]
     /**
-     * <p>
-     * Overload the {@link DefaultClientAttribute#setUpId(String)} method.
-     * </p>
-     * <p>
-     * As the attributeType has already been set, we have to be sure that the 
-     * argument is compatible with the attributeType's name. 
-     * </p>
-     * <p>
-     * If the given ID is not compatible with the attributeType's possible
-     * names, the previously loaded ID will be kept.
-     * </p>
-     *
-     * @param upId The attribute ID
+     * Create a new instance of a EntryAttribute, without ID nor value.
+     * 
+     * @param attributeType the attributeType for the empty attribute added into the entry
      */
-    public void setUpId( String upId )
+    public DefaultServerAttribute( AttributeType attributeType )
     {
-        if ( !StringTools.isEmpty( StringTools.trim( upId  ) ) )
+        if ( attributeType == null )
         {
-            if ( attributeType.getName() == null )
-            {
-                // If the name is null, then we may have to store an OID
-                if ( OID.isOID( upId )  && attributeType.getOid().equals( upId ) )
-                {
-                    // Everything is fine, store the upId.
-                    // This should not happen...
-                    super.setUpId( upId );
-                    
-                }
-            }
-            else
-            {
-                // We have at least one name. Check that the normalized upId
-                // is one of those names. Otherwise, the upId may be an OID too.
-                // In this case, it must be equals to the attributeType OID.
-                String normUpId = StringTools.lowerCaseAscii( StringTools.trim( upId ) );
-                
-                for ( String atId:attributeType.getNamesRef() )
-                {
-                    if ( atId.equalsIgnoreCase( normUpId ) )
-                    {
-                        // Found ! We can store the upId and get out
-                        super.setUpId( upId );
-                        return;
-                    }
-                }
-                
-                // Last case, the UpId is an OID
-                if ( OID.isOID( normUpId ) && attributeType.getOid().equals( normUpId ) )
-                {
-                    // We have an OID : stores it
-                    super.setUpId( upId );
-                }
-            }
+            throw new IllegalArgumentException( "The AttributeType parameter should not be null" );
         }
+        
+        setAttributeType( attributeType );
     }
-    
-    
+
+
     /**
-     * <p>
-     * Set the user provided ID. If we have none, the upId is assigned
-     * the attributetype's name. If it does not have any name, we will
-     * use the OID.
-     * </p>
-     * <p>
-     * If we have an upId and an AttributeType, they must be compatible. :
-     *  - if the upId is an OID, it must be the AttributeType's OID
-     *  - otherwise, its normalized form must be equals to ones of
-     *  the attributeType's names.
-     * </p>
-     * <p>
-     * In any case, the ATtributeType will be changed. The caller is responsible for
-     * the present values to be compatoble with the new AttributeType.
-     * </p>
-     *
-     * @param upId The attribute ID
-     * @param attributeType The associated attributeType
+     * Create a new instance of a EntryAttribute, without value.
+     * 
+     * @param upId the ID for the added attributeType
+     * @param attributeType the added AttributeType
      */
-    public void setUpId( String upId, AttributeType attributeType )
+    public DefaultServerAttribute( String upId, AttributeType attributeType )
     {
-        if ( StringTools.isEmpty( StringTools.trim( upId  ) ) )
+        if ( attributeType == null ) 
         {
-            super.setUpId( getUpId( attributeType ) );
-            this.attributeType = attributeType;
+            String message = "The AttributeType parameter should not be null";
+            LOG.error( message );
+            throw new IllegalArgumentException( message );
         }
-        else
-        {
-            String name = attributeType.getName();
-            
-            if ( name == null )
-            {
-                // If the name is null, then we may have to store an OID
-                if ( OID.isOID( upId )  && attributeType.getOid().equals( upId ) )
-                {
-                    //  Everything is fine, store the upId. 
-                    super.setUpId( upId );
-                    this.attributeType = attributeType;
-                }
-                else
-                {
-                    // We have a difference or the upId is not a valid OID :
-                    // we will use the attributeTypeOID in this case.
-                    LOG.warn( "The upID ({}) is not an OID or is different from the AttributeType OID({})",
-                        upId, attributeType.getOid() );
-                    super.setUpId( attributeType.getOid() );
-                    this.attributeType = attributeType;
-                }
-            }
-            else
-            {
-                // We have at least one name. Check that the normalized upId
-                // is one of those names. Otherwise, the upId may be an OID too.
-                // In this case, it must be equals to the attributeType OID.
-                String normUpId = StringTools.lowerCaseAscii( StringTools.trim( upId ) );
-                
-                for ( String atId:attributeType.getNamesRef() )
-                {
-                    if ( atId.equalsIgnoreCase( normUpId ) )
-                    {
-                        // Found ! We can store the upId and get out
-                        super.setUpId( upId );
-                        this.attributeType = attributeType;
-                        return;
-                    }
-                }
-    
-                // UpId was not found in names. It should be an OID, or if not, we 
-                // will use the AttributeType name.
-                if ( OID.isOID( normUpId ) && attributeType.getOid().equals( normUpId ) )
-                {
-                    // We have an OID : stores it
-                    super.setUpId( upId );
-                    this.attributeType = attributeType;
-                }
-                else
-                {
-                    String message = "The upID (" + upId + ") is not an OID or is different from the AttributeType OID (" + 
-                                        attributeType.getOid() + ")";
-                    // Not a valid OID : use the AttributeTypes OID name instead
-                    LOG.error( message );
-                    throw new IllegalArgumentException( message );
-                }
-            }
-        }
-    }
-    
-    
-    /**
-     * <p>
-     * Set the attribute type associated with this ServerAttribute.
-     * </p>
-     * <p>
-     * The current attributeType will be replaced. It is the responsibility of
-     * the caller to insure that the existing values are compatible with the new
-     * AttributeType
-     * </p>
-     *
-     * @param attributeType the attributeType associated with this entry attribute
-     */
-    public void setAttributeType( AttributeType attributeType )
-    {
-        if ( attributeType == null )
-        {
-            throw new IllegalArgumentException( "The AttributeType parameter should not be null" );
-        }
-
-        this.attributeType = attributeType;
-        setUpId( null, attributeType );
-        
-        try
-        {
-            if ( attributeType.getSyntax().isHumanReadable() )
-            {
-                isHR = true;
-            }
-            else
-            {
-                isHR = false;
-            }
-        }
-        catch ( NamingException ne )
-        {
-            // If we have an exception while trying to get the Syntax for this attribute
-            // just set it as Binary
-            isHR = false;
-        }
-    }
-    
-    
-    /**
-     * Get the attribute type associated with this ServerAttribute.
-     *
-     * @return the attributeType associated with this entry attribute
-     */
-    public AttributeType getAttributeType()
-    {
-        return attributeType;
-    }
-    
-    
-    // maybe have some additional convenience constructors which take
-    // an initial value as a string or a byte[]
-    /**
-     * Create a new instance of a EntryAttribute, without ID nor value.
-     * 
-     * @param attributeType the attributeType for the empty attribute added into the entry
-     */
-    public DefaultServerAttribute( AttributeType attributeType )
-    {
-        if ( attributeType == null )
-        {
-            throw new IllegalArgumentException( "The AttributeType parameter should not be null" );
-        }
-        
-        setAttributeType( attributeType );
-    }
-
-
-    /**
-     * Create a new instance of a EntryAttribute, without value.
-     * 
-     * @param upId the ID for the added attributeType
-     * @param attributeType the added AttributeType
-     */
-    public DefaultServerAttribute( String upId, AttributeType attributeType )
-    {
-        if ( attributeType == null ) 
-        {
-            String message = "The AttributeType parameter should not be null";
-            LOG.error( message );
-            throw new IllegalArgumentException( message );
-        }
-
-        setAttributeType( attributeType );
-        setUpId( upId );
-    }
-
-
-    /**
-     * Doc me more!
-     *
-     * If the value does not correspond to the same attributeType, then it's
-     * wrapped value is copied into a new Value which uses the specified
-     * attributeType.
-     *
-     * @param attributeType the attribute type according to the schema
-     * @param vals an initial set of values for this attribute
-     */
-    public DefaultServerAttribute( AttributeType attributeType, Value<?>... vals )
-    {
-        this( null, attributeType, vals );
-    }
-
-
-    /**
-     * Doc me more!
-     *
-     * If the value does not correspond to the same attributeType, then it's
-     * wrapped value is copied into a new Value which uses the specified
-     * attributeType.
-     * 
-     * Otherwise, the value is stored, but as a reference. It's not a copy.
-     *
-     * @param upId the ID of the added attribute
-     * @param attributeType the attribute type according to the schema
-     * @param vals an initial set of values for this attribute
-     */
-    public DefaultServerAttribute( String upId, AttributeType attributeType, Value<?>... vals )
-    {
-        if ( attributeType == null )
+
+        setAttributeType( attributeType );
+        setUpId( upId );
+    }
+
+
+    /**
+     * Doc me more!
+     *
+     * If the value does not correspond to the same attributeType, then it's
+     * wrapped value is copied into a new Value which uses the specified
+     * attributeType.
+     *
+     * @param attributeType the attribute type according to the schema
+     * @param vals an initial set of values for this attribute
+     */
+    public DefaultServerAttribute( AttributeType attributeType, Value<?>... vals )
+    {
+        this( null, attributeType, vals );
+    }
+
+
+    /**
+     * Doc me more!
+     *
+     * If the value does not correspond to the same attributeType, then it's
+     * wrapped value is copied into a new Value which uses the specified
+     * attributeType.
+     * 
+     * Otherwise, the value is stored, but as a reference. It's not a copy.
+     *
+     * @param upId the ID of the added attribute
+     * @param attributeType the attribute type according to the schema
+     * @param vals an initial set of values for this attribute
+     */
+    public DefaultServerAttribute( String upId, AttributeType attributeType, Value<?>... vals )
+    {
+        if ( attributeType == null )
         {
             throw new IllegalArgumentException( "The AttributeType parameter should not be null" );
         }
@@ -520,70 +302,115 @@
     }
     
     
-    /**
-     * Clone an attribute. 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
-     * 
-     * @return a clone of the current attribute
-     */
-    public ServerAttribute clone()
-    {
-        // clone the structure by cloner the inherited class
-        ServerAttribute clone = (ServerAttribute)super.clone();
-        
-        // We are done !
-        return clone;
-    }
-
-
+    //-------------------------------------------------------------------------
+    // API
+    //-------------------------------------------------------------------------
     /**
      * <p>
-     * Overload the ClientAttribte isHR method : we can't change this flag
-     * for a ServerAttribute, as the HR is already set using the AttributeType.
-     * Set the attribute to Human Readable or to Binary. 
+     * Adds some values to this attribute. If the new values are already present in
+     * the attribute values, the method has no effect.
      * </p>
-     * 
-     * @param isHR <code>true</code> for a Human Readable attribute, 
-     * <code>false</code> for a Binary attribute.
-     */
-    public void setHR( boolean isHR )
-    {
-        // Do nothing...
-    }
-
-    
-    /**
      * <p>
-     * Checks to see if this attribute is valid along with the values it contains.
+     * The new values are added at the end of list of values.
      * </p>
      * <p>
-     * An attribute is valid if :
-     * <li>All of its values are valid with respect to the attributeType's syntax checker</li>
-     * <li>If the attributeType is SINGLE-VALUE, then no more than a value should be present</li>
-     *</p>
-     * @return true if the attribute and it's values are valid, false otherwise
-     * @throws NamingException if there is a failure to check syntaxes of values
+     * This method returns the number of values that were added.
+     * </p>
+     * <p>
+     * If the value's type is different from the attribute's type,
+     * the value is not added.
+     * </p>
+     * It's the responsibility of the caller to check if the stored
+     * values are consistent with the attribute's type.
+     * <p>
+     *
+     * @param vals some new values to be added which may be null
+     * @return the number of added values, or 0 if none has been added
      */
-    public boolean isValid() throws NamingException
+    public int add( byte[]... vals )
     {
-        // First check if the attribute has more than one value
-        // if the attribute is supposed to be SINGLE_VALUE
-        if ( attributeType.isSingleValue() && ( values.size() > 1 ) )
-        {
-            return false;
-        }
-
-        for ( Value<?> value : values )
+        if ( !isHR )
         {
-            if ( ! value.isValid() )
+            int nbAdded = 0;
+            
+            for ( byte[] val:vals )
             {
-                return false;
+                Value<?> value = new ServerBinaryValue( attributeType, val );
+                
+                try
+                {
+                    value.normalize();
+                }
+                catch( NamingException ne )
+                {
+                    // The value can't be normalized : we don't add it.
+                    LOG.error( "The value '" + val + "' can't be normalized, it hasn't been added" );
+                    return 0;
+                }
+                
+                if ( add( value ) != 0 )
+                {
+                    nbAdded++;
+                }
+                else
+                {
+                    LOG.error( "The value '" + val + "' is incorrect, it hasn't been added" );
+                }
             }
+            
+            return nbAdded;
         }
+        else
+        {
+            // We can't add Binary values into a String serverAttribute
+            return 0;
+        }
+    }    
 
-        return true;
-    }
+
+    /**
+     * <p>
+     * Adds some values to this attribute. If the new values are already present in
+     * the attribute values, the method has no effect.
+     * </p>
+     * <p>
+     * The new values are added at the end of list of values.
+     * </p>
+     * <p>
+     * This method returns the number of values that were added.
+     * </p>
+     * If the value's type is different from the attribute's type,
+     * the value is not added.
+     *
+     * @param vals some new values to be added which may be null
+     * @return the number of added values, or 0 if none has been added
+     */
+    public int add( String... vals )
+    {
+        if ( isHR )
+        {
+            int nbAdded = 0;
+            
+            for ( String val:vals )
+            {
+                if ( add( new ServerStringValue( attributeType, val ) ) != 0 )
+                {
+                    nbAdded++;
+                }
+                else
+                {
+                    LOG.error( "The value '" + val + "' is incorrect, it hasn't been added" );
+                }
+            }
+            
+            return nbAdded;
+        }
+        else
+        {
+            // We can't add String values into a Binary serverAttribute
+            return 0;
+        }
+    }    
 
 
     /**
@@ -693,111 +520,101 @@
 
 
     /**
+     * Remove all the values from this attribute type, including a 
+     * null value. 
+     */
+    public void clear()
+    {
+        values.clear();
+    }
+
+
+    /**
      * <p>
-     * Adds some values to this attribute. If the new values are already present in
-     * the attribute values, the method has no effect.
-     * </p>
-     * <p>
-     * The new values are added at the end of list of values.
+     * Indicates whether all the specified values are attribute's values. If
+     * at least one value is not an attribute's value, this method will return 
+     * <code>false</code>
      * </p>
      * <p>
-     * This method returns the number of values that were added.
+     * If the Attribute is HR, this method will returns <code>false</code>
      * </p>
-     * If the value's type is different from the attribute's type,
-     * the value is not added.
      *
-     * @param vals some new values to be added which may be null
-     * @return the number of added values, or 0 if none has been added
+     * @param vals the values
+     * @return true if this attribute contains all the values, otherwise false
      */
-    public int add( String... vals )
+    public boolean contains( byte[]... vals )
     {
-        if ( isHR )
+        if ( !isHR )
         {
-            int nbAdded = 0;
-            
-            for ( String val:vals )
+            // Iterate through all the values, and quit if we 
+            // don't find one in the values
+            for ( byte[] val:vals )
             {
-                if ( add( new ServerStringValue( attributeType, val ) ) != 0 )
+                ServerBinaryValue value = new ServerBinaryValue( attributeType, val );
+                
+                try
                 {
-                    nbAdded++;
+                    value.normalize();
                 }
-                else
+                catch ( NamingException ne )
                 {
-                    LOG.error( "The value '" + val + "' is incorrect, it hasn't been added" );
+                    return false;
+                }
+                
+                if ( !values.contains( value ) )
+                {
+                    return false;
                 }
             }
             
-            return nbAdded;
+            return true;
         }
         else
         {
-            // We can't add String values into a Binary serverAttribute
-            return 0;
+            return false;
         }
-    }    
+    }
     
     
     /**
      * <p>
-     * Adds some values to this attribute. If the new values are already present in
-     * the attribute values, the method has no effect.
-     * </p>
-     * <p>
-     * The new values are added at the end of list of values.
-     * </p>
-     * <p>
-     * This method returns the number of values that were added.
+     * Indicates whether all the specified values are attribute's values. If
+     * at least one value is not an attribute's value, this method will return 
+     * <code>false</code>
      * </p>
      * <p>
-     * If the value's type is different from the attribute's type,
-     * the value is not added.
+     * If the Attribute is not HR, this method will returns <code>false</code>
      * </p>
-     * It's the responsibility of the caller to check if the stored
-     * values are consistent with the attribute's type.
-     * <p>
      *
-     * @param vals some new values to be added which may be null
-     * @return the number of added values, or 0 if none has been added
+     * @param vals the values
+     * @return true if this attribute contains all the values, otherwise false
      */
-    public int add( byte[]... vals )
+    public boolean contains( String... vals )
     {
-        if ( !isHR )
+        if ( isHR )
         {
-            int nbAdded = 0;
-            
-            for ( byte[] val:vals )
+            // Iterate through all the values, and quit if we 
+            // don't find one in the values
+            for ( String val:vals )
             {
-                if ( add( new ServerBinaryValue( attributeType, val ) ) != 0 )
-                {
-                    nbAdded++;
-                }
-                else
+                ServerStringValue value = new ServerStringValue( attributeType, val );
+                
+                if ( !values.contains( value ) )
                 {
-                    LOG.error( "The value '" + val + "' is incorrect, it hasn't been added" );
+                    return false;
                 }
             }
             
-            return nbAdded;
+            return true;
         }
         else
         {
-            // We can't add Binary values into a String serverAttribute
-            return 0;
+            return false;
         }
-    }    
+    }
     
     
     /**
-     * Remove all the values from this attribute type, including a 
-     * null value. 
-     */
-    public void clear()
-    {
-        values.clear();
-    }
-
-
-    /**
      * <p>
      * Indicates whether the specified values are some of the attribute's values.
      * </p>
@@ -840,230 +657,667 @@
                     return false;
                 }
             }
-        }
-        else
-        {
-            for ( Value<?> val:vals )
+        }
+        else
+        {
+            for ( Value<?> val:vals )
+            {
+                if ( val instanceof ClientBinaryValue )
+                {
+                    if ( !values.contains( val ) )
+                    {
+                        return false;
+                    }
+                }
+                else
+                {
+                    // Not a Binary value
+                    return false;
+                }
+            }
+        }
+        
+        return true;
+    }
+
+
+    /**
+     * Get the attribute type associated with this ServerAttribute.
+     *
+     * @return the attributeType associated with this entry attribute
+     */
+    public AttributeType getAttributeType()
+    {
+        return attributeType;
+    }
+    
+    
+    /**
+     * <p>
+     * Check if the current attribute type is of the expected attributeType
+     * </p>
+     * <p>
+     * This method won't tell if the current attribute is a descendant of 
+     * the attributeType. For instance, the "CN" serverAttribute will return
+     * false if we ask if it's an instance of "Name". 
+     * </p> 
+     *
+     * @param attributeId The AttributeType ID to check
+     * @return True if the current attribute is of the expected attributeType
+     * @throws InvalidAttributeValueException If there is no AttributeType
+     */
+    public boolean instanceOf( String attributeId ) throws InvalidAttributeValueException
+    {
+        String trimmedId = StringTools.trim( attributeId );
+        
+        if ( StringTools.isEmpty( trimmedId ) )
+        {
+            return false;
+        }
+        
+        String normId = StringTools.lowerCaseAscii( trimmedId );
+        
+        for ( String name:attributeType.getNamesRef() )
+        {
+            if ( normId.equalsIgnoreCase( name ) )
+            {
+                return true;
+            }
+        }
+        
+        return normId.equalsIgnoreCase( attributeType.getOid() );
+    }
+    
+
+    /**
+     * <p>
+     * Checks to see if this attribute is valid along with the values it contains.
+     * </p>
+     * <p>
+     * An attribute is valid if :
+     * <li>All of its values are valid with respect to the attributeType's syntax checker</li>
+     * <li>If the attributeType is SINGLE-VALUE, then no more than a value should be present</li>
+     *</p>
+     * @return true if the attribute and it's values are valid, false otherwise
+     * @throws NamingException if there is a failure to check syntaxes of values
+     */
+    public boolean isValid() throws NamingException
+    {
+        // First check if the attribute has more than one value
+        // if the attribute is supposed to be SINGLE_VALUE
+        if ( attributeType.isSingleValue() && ( values.size() > 1 ) )
+        {
+            return false;
+        }
+
+        for ( Value<?> value : values )
+        {
+            if ( ! value.isValid() )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * @see EntryAttribute#remove(byte[]...)
+     * 
+     * @return <code>true</code> if all the values shave been removed from this attribute
+     */
+    public boolean remove( byte[]... vals )
+    {
+        if ( isHR ) 
+        {
+            return false;
+        }
+        
+        boolean removed = true;
+        
+        for ( byte[] val:vals )
+        {
+            ServerBinaryValue value = new ServerBinaryValue( attributeType, val );
+            removed &= values.remove( value );
+        }
+        
+        return removed;
+    }
+
+
+    /**
+     * @see EntryAttribute#remove(String...)
+     * 
+     * @return <code>true</code> if all the values shave been removed from this attribute
+     */
+    public boolean remove( String... vals )
+    {
+        if ( !isHR )
+        {
+            return false;
+        }
+        
+        boolean removed = true;
+        
+        for ( String val:vals )
+        {
+            ServerStringValue value = new ServerStringValue( attributeType, val );
+            removed &= values.remove( value );
+        }
+        
+        return removed;
+    }
+
+
+    /**
+     * @see EntryAttribute#remove(org.apache.directory.shared.ldap.entry.Value...)
+     * 
+     * @return <code>true</code> if all the values shave been removed from this attribute
+     */
+    public boolean remove( Value<?>... vals )
+    {
+        boolean removed = true;
+        
+        // Loop through all the values to remove. If one of
+        // them is not present, the method will return false.
+        // As the attribute may be HR or not, we have two separated treatments
+        if ( isHR )
+        {
+            for ( Value<?> val:vals )
+            {
+                if ( val instanceof ClientStringValue )
+                {
+                    ServerStringValue ssv = new ServerStringValue( attributeType, (String)val.get() );
+                    removed &= values.remove( ssv );
+                }
+                else if ( val instanceof ServerStringValue )
+                {
+                    removed &= values.remove( val );
+                }
+                else
+                {
+                    removed = false;
+                }
+            }
+        }
+        else
+        {
+            for ( Value<?> val:vals )
+            {
+                if ( val instanceof ClientBinaryValue )
+                {
+                    ServerBinaryValue sbv = new ServerBinaryValue( attributeType, (byte[])val.get() );
+                    removed &= values.remove( sbv );
+                }
+                else if ( val instanceof ServerBinaryValue )
+                {
+                    removed &= values.remove( val );
+                }
+                else
+                {
+                    removed = false;
+                }
+            }
+        }
+        
+        return removed;
+    }
+
+
+    
+    /**
+     * <p>
+     * Set the attribute type associated with this ServerAttribute.
+     * </p>
+     * <p>
+     * The current attributeType will be replaced. It is the responsibility of
+     * the caller to insure that the existing values are compatible with the new
+     * AttributeType
+     * </p>
+     *
+     * @param attributeType the attributeType associated with this entry attribute
+     */
+    public void setAttributeType( AttributeType attributeType )
+    {
+        if ( attributeType == null )
+        {
+            throw new IllegalArgumentException( "The AttributeType parameter should not be null" );
+        }
+
+        this.attributeType = attributeType;
+        setUpId( null, attributeType );
+        
+        try
+        {
+            if ( attributeType.getSyntax().isHumanReadable() )
+            {
+                isHR = true;
+            }
+            else
+            {
+                isHR = false;
+            }
+        }
+        catch ( NamingException ne )
+        {
+            // If we have an exception while trying to get the Syntax for this attribute
+            // just set it as Binary
+            isHR = false;
+        }
+    }
+    
+    
+    /**
+     * <p>
+     * Overload the ClientAttribte isHR method : we can't change this flag
+     * for a ServerAttribute, as the HR is already set using the AttributeType.
+     * Set the attribute to Human Readable or to Binary. 
+     * </p>
+     * 
+     * @param isHR <code>true</code> for a Human Readable attribute, 
+     * <code>false</code> for a Binary attribute.
+     */
+    public void setHR( boolean isHR )
+    {
+        // Do nothing...
+    }
+
+    
+    /**
+     * <p>
+     * Overload the {@link DefaultClientAttribute#setId(String)} method.
+     * </p>
+     * <p>
+     * As the attributeType has already been set, we have to be sure that the 
+     * argument is compatible with the attributeType's name. 
+     * </p>
+     * <p>
+     * If the given ID is not compatible with the attributeType's possible
+     * names, the previously loaded ID will be kept.
+     * </p>
+     *
+     * @param id The attribute ID
+     */
+    public void setId( String id )
+    {
+        if ( !StringTools.isEmpty( StringTools.trim( id  ) ) )
+        {
+            if ( attributeType.getName() == null )
+            {
+                // If the name is null, then we may have to store an OID
+                if ( OID.isOID( id )  && attributeType.getOid().equals( id ) )
+                {
+                    // Everything is fine, store the upId.
+                    // This should not happen...
+                    super.setId( id );
+                }
+            }
+            else
+            {
+                // We have at least one name. Check that the normalized upId
+                // is one of those names. Otherwise, the upId may be an OID too.
+                // In this case, it must be equals to the attributeType OID.
+                String normId = StringTools.lowerCaseAscii( StringTools.trim( id ) );
+                
+                for ( String atName:attributeType.getNamesRef() )
+                {
+                    if ( atName.equalsIgnoreCase( normId ) )
+                    {
+                        // Found ! We can store the upId and get out
+                        super.setId( normId );
+                        return;
+                    }
+                }
+                
+                // Last case, the UpId is an OID
+                if ( OID.isOID( normId ) && attributeType.getOid().equals( normId ) )
+                {
+                    // We have an OID : stores it
+                    super.setUpId( normId );
+                }
+                else
+                {
+                    // The id is incorrect : this is not allowed 
+                    throw new IllegalArgumentException( "The ID '" + id + "'is incompatible with the AttributeType's id '" + 
+                        attributeType.getName() + "'" );
+                }
+            }
+        }
+        else
+        {
+            throw new IllegalArgumentException( "An ID cannnot be null, empty, or resolved to an emtpy" +
+            " value when trimmed" );
+        }
+    }
+    
+    
+    /**
+     * <p>
+     * Overload the {@link DefaultClientAttribute#setUpId(String)} method.
+     * </p>
+     * <p>
+     * As the attributeType has already been set, we have to be sure that the 
+     * argument is compatible with the attributeType's name. 
+     * </p>
+     * <p>
+     * If the given ID is not compatible with the attributeType's possible
+     * names, the previously loaded ID will be kept.
+     * </p>
+     *
+     * @param upId The attribute ID
+     */
+    public void setUpId( String upId )
+    {
+        if ( !StringTools.isEmpty( StringTools.trim( upId  ) ) )
+        {
+            if ( attributeType.getName() == null )
+            {
+                // If the name is null, then we may have to store an OID
+                if ( OID.isOID( upId )  && attributeType.getOid().equals( upId ) )
+                {
+                    // Everything is fine, store the upId.
+                    // This should not happen...
+                    super.setUpId( upId );
+                    
+                }
+            }
+            else
+            {
+                // We have at least one name. Check that the normalized upId
+                // is one of those names. Otherwise, the upId may be an OID too.
+                // In this case, it must be equals to the attributeType OID.
+                String normUpId = StringTools.lowerCaseAscii( StringTools.trim( upId ) );
+                
+                for ( String atId:attributeType.getNamesRef() )
+                {
+                    if ( atId.equalsIgnoreCase( normUpId ) )
+                    {
+                        // Found ! We can store the upId and get out
+                        super.setUpId( upId );
+                        return;
+                    }
+                }
+                
+                // Last case, the UpId is an OID
+                if ( OID.isOID( normUpId ) && attributeType.getOid().equals( normUpId ) )
+                {
+                    // We have an OID : stores it
+                    super.setUpId( upId );
+                }
+            }
+        }
+    }
+    
+    
+    /**
+     * <p>
+     * Set the user provided ID. If we have none, the upId is assigned
+     * the attributetype's name. If it does not have any name, we will
+     * use the OID.
+     * </p>
+     * <p>
+     * If we have an upId and an AttributeType, they must be compatible. :
+     *  - if the upId is an OID, it must be the AttributeType's OID
+     *  - otherwise, its normalized form must be equals to ones of
+     *  the attributeType's names.
+     * </p>
+     * <p>
+     * In any case, the ATtributeType will be changed. The caller is responsible for
+     * the present values to be compatoble with the new AttributeType.
+     * </p>
+     *
+     * @param upId The attribute ID
+     * @param attributeType The associated attributeType
+     */
+    public void setUpId( String upId, AttributeType attributeType )
+    {
+        if ( StringTools.isEmpty( StringTools.trim( upId  ) ) )
+        {
+            super.setUpId( getUpId( attributeType ) );
+            this.attributeType = attributeType;
+        }
+        else
+        {
+            String name = attributeType.getName();
+            
+            if ( name == null )
+            {
+                // If the name is null, then we may have to store an OID
+                if ( OID.isOID( upId )  && attributeType.getOid().equals( upId ) )
+                {
+                    //  Everything is fine, store the upId. 
+                    super.setUpId( upId );
+                    this.attributeType = attributeType;
+                }
+                else
+                {
+                    // We have a difference or the upId is not a valid OID :
+                    // we will use the attributeTypeOID in this case.
+                    LOG.warn( "The upID ({}) is not an OID or is different from the AttributeType OID({})",
+                        upId, attributeType.getOid() );
+                    super.setUpId( attributeType.getOid() );
+                    this.attributeType = attributeType;
+                }
+            }
+            else
             {
-                if ( val instanceof ClientBinaryValue )
+                // We have at least one name. Check that the normalized upId
+                // is one of those names. Otherwise, the upId may be an OID too.
+                // In this case, it must be equals to the attributeType OID.
+                String normUpId = StringTools.lowerCaseAscii( StringTools.trim( upId ) );
+                
+                for ( String atId:attributeType.getNamesRef() )
                 {
-                    if ( !values.contains( val ) )
+                    if ( atId.equalsIgnoreCase( normUpId ) )
                     {
-                        return false;
+                        // Found ! We can store the upId and get out
+                        super.setUpId( upId );
+                        this.attributeType = attributeType;
+                        return;
                     }
                 }
+    
+                // UpId was not found in names. It should be an OID, or if not, we 
+                // will use the AttributeType name.
+                if ( OID.isOID( normUpId ) && attributeType.getOid().equals( normUpId ) )
+                {
+                    // We have an OID : stores it
+                    super.setUpId( upId );
+                    this.attributeType = attributeType;
+                }
                 else
                 {
-                    // Not a Binary value
-                    return false;
+                    String message = "The upID (" + upId + ") is not an OID or is different from the AttributeType OID (" + 
+                                        attributeType.getOid() + ")";
+                    // Not a valid OID : use the AttributeTypes OID name instead
+                    LOG.error( message );
+                    throw new IllegalArgumentException( message );
                 }
             }
         }
-        
-        return true;
     }
 
 
     /**
-     * <p>
-     * Indicates whether all the specified values are attribute's values. If
-     * at least one value is not an attribute's value, this method will return 
-     * <code>false</code>
-     * </p>
-     * <p>
-     * If the Attribute is not HR, this method will returns <code>false</code>
-     * </p>
+     * Convert the ServerAttribute to a ClientAttribute
      *
-     * @param vals the values
-     * @return true if this attribute contains all the values, otherwise false
+     * @return An instance of ClientAttribute
      */
-    public boolean contains( String... vals )
+    public EntryAttribute toClientAttribute()
     {
-        if ( isHR )
+        // Create the new EntryAttribute
+        EntryAttribute clientAttribute = new DefaultClientAttribute( upId );
+        
+        // Copy the values
+        for ( Value<?> value:this )
         {
-            // Iterate through all the values, and quit if we 
-            // don't find one in the values
-            for ( String val:vals )
+            Value<?> clientValue = null;
+            
+            if ( value instanceof ServerStringValue )
             {
-                ServerStringValue value = new ServerStringValue( attributeType, val );
-                
-                if ( !values.contains( value ) )
-                {
-                    return false;
-                }
+                clientValue = new ClientStringValue( (String)value.get() );
+            }
+            else
+            {
+                clientValue = new ClientBinaryValue( (byte[])value.get() );
             }
             
-            return true;
-        }
-        else
-        {
-            return false;
+            clientAttribute.add( clientValue );
         }
+        
+        return clientAttribute;
     }
-    
+
+
+    //-------------------------------------------------------------------------
+    // Serialization methods
+    //-------------------------------------------------------------------------
     
     /**
-     * <p>
-     * Indicates whether all the specified values are attribute's values. If
-     * at least one value is not an attribute's value, this method will return 
-     * <code>false</code>
-     * </p>
-     * <p>
-     * If the Attribute is HR, this method will returns <code>false</code>
-     * </p>
-     *
-     * @param vals the values
-     * @return true if this attribute contains all the values, otherwise false
+     * @see java.io.Externalizable#writeExternal(ObjectOutput)
+     * 
+     * We can't use this method for a ServerAttribute, as we have to feed the value
+     * with an AttributeType object
      */
-    public boolean contains( byte[]... vals )
+    public void writeExternal( ObjectOutput out ) throws IOException
     {
-        if ( !isHR )
-        {
-            // Iterate through all the values, and quit if we 
-            // don't find one in the values
-            for ( byte[] val:vals )
-            {
-                ServerBinaryValue value = new ServerBinaryValue( attributeType, val );
-                
-                if ( !values.contains( value ) )
-                {
-                    return false;
-                }
-            }
-            
-            return true;
-        }
-        else
-        {
-            return false;
-        }
+        throw new IllegalStateException( "Cannot use standard serialization for a ServerAttribute" );
     }
     
     
     /**
-     * @see EntryAttribute#remove(org.apache.directory.shared.ldap.entry.Value...)
+     * @see Externalizable#writeExternal(ObjectOutput)
+     * <p>
+     * 
+     * This is the place where we serialize attributes, and all theirs
+     * elements. 
+     * 
+     * The inner structure is the same as the client attribute, but we can't call
+     * it as we won't be able to serialize the serverValues
      * 
-     * @return <code>true</code> if all the values shave been removed from this attribute
      */
-    public boolean remove( Value<?>... vals )
+    public void serialize( ObjectOutput out ) throws IOException
     {
-        boolean removed = true;
+        // Write the UPId (the id will be deduced from the upID)
+        out.writeUTF( upId );
         
-        // Loop through all the values to remove. If one of
-        // them is not present, the method will return false.
-        // As the attribute may be HR or not, we have two separated treatments
-        if ( isHR )
+        // Write the HR flag, if not null
+        if ( isHR != null )
         {
-            for ( Value<?> val:vals )
-            {
-                if ( val instanceof ClientStringValue )
-                {
-                    ServerStringValue ssv = new ServerStringValue( attributeType, (String)val.get() );
-                    removed &= values.remove( ssv );
-                }
-                else if ( val instanceof ServerStringValue )
-                {
-                    removed &= values.remove( val );
-                }
-                else
-                {
-                    removed = false;
-                }
-            }
+            out.writeBoolean( true );
+            out.writeBoolean( isHR );
         }
         else
         {
-            for ( Value<?> val:vals )
+            out.writeBoolean( false );
+        }
+        
+        // Write the number of values
+        out.writeInt( size() );
+        
+        if ( size() > 0 ) 
+        {
+            // Write each value
+            for ( Value<?> value:values )
             {
-                if ( val instanceof ClientBinaryValue )
-                {
-                    ServerBinaryValue sbv = new ServerBinaryValue( attributeType, (byte[])val.get() );
-                    removed &= values.remove( sbv );
-                }
-                else if ( val instanceof ServerBinaryValue )
+                // Write the value, using the correct method
+                if ( value instanceof ServerStringValue )
                 {
-                    removed &= values.remove( val );
+                    ((ServerStringValue)value).serialize( out );
                 }
                 else
                 {
-                    removed = false;
+                    ((ServerBinaryValue)value).serialize( out );
                 }
             }
         }
         
-        return removed;
+        out.flush();
     }
 
-
+    
     /**
-     * @see EntryAttribute#remove(byte[]...)
+     * @see java.io.Externalizable#readExternal(ObjectInput)
      * 
-     * @return <code>true</code> if all the values shave been removed from this attribute
+     * We can't use this method for a ServerAttribute, as we have to feed the value
+     * with an AttributeType object
      */
-    public boolean remove( byte[]... vals )
+    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
     {
-        if ( isHR ) 
-        {
-            return false;
-        }
-        
-        boolean removed = true;
-        
-        for ( byte[] val:vals )
-        {
-            ServerBinaryValue value = new ServerBinaryValue( attributeType, val );
-            removed &= values.remove( value );
-        }
-        
-        return removed;
+        throw new IllegalStateException( "Cannot use standard serialization for a ServerAttribute" );
     }
-
-
+    
+    
     /**
-     * @see EntryAttribute#remove(String...)
-     * 
-     * @return <code>true</code> if all the values shave been removed from this attribute
+     * @see Externalizable#readExternal(ObjectInput)
      */
-    public boolean remove( String... vals )
+    public void deserialize( ObjectInput in ) throws IOException, ClassNotFoundException
     {
-        if ( !isHR )
-        {
-            return false;
-        }
+        // Read the ID and the UPId
+        upId = in.readUTF();
         
-        boolean removed = true;
+        // Compute the id
+        setUpId( upId );
         
-        for ( String val:vals )
+        // Read the HR flag, if not null
+        if ( in.readBoolean() )
         {
-            ServerStringValue value = new ServerStringValue( attributeType, val );
-            removed &= values.remove( value );
+            isHR = in.readBoolean();
         }
-        
-        return removed;
-    }
 
+        // Read the number of values
+        int nbValues = in.readInt();
 
+        if ( nbValues > 0 )
+        {
+            for ( int i = 0; i < nbValues; i++ )
+            {
+                Value<?> value = null;
+                
+                if ( isHR )
+                {
+                    value  = new ServerStringValue( attributeType );
+                    ((ServerStringValue)value).deserialize( in );
+                }
+                else
+                {
+                    value  = new ServerBinaryValue( attributeType );
+                    ((ServerBinaryValue)value).deserialize( in );
+                }
+                
+                try
+                {
+                    value.normalize();
+                }
+                catch ( NamingException ne )
+                {
+                    // Do nothing...
+                }
+                    
+                values.add( value );
+            }
+        }
+    }
+    
+    
     //-------------------------------------------------------------------------
-    // Overloaded Object classes
+    // Overloaded Object class methods
     //-------------------------------------------------------------------------
     /**
-     * The hashCode is based on the id, the isHR flag and 
-     * on the internal values.
-     *  
-     * @see Object#hashCode()
+     * Clone an attribute. 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
      * 
-     * @return the instance's hash code 
+     * @return a clone of the current attribute
      */
-    public int hashCode()
+    public ServerAttribute clone()
     {
-        int h = super.hashCode();
-        
-        if ( attributeType != null )
-        {
-            h = h*17 + attributeType.hashCode();
-        }
+        // clone the structure by cloner the inherited class
+        ServerAttribute clone = (ServerAttribute)super.clone();
         
-        return h;
+        // We are done !
+        return clone;
     }
 
 
@@ -1109,6 +1363,27 @@
     
     
     /**
+     * The hashCode is based on the id, the isHR flag and 
+     * on the internal values.
+     *  
+     * @see Object#hashCode()
+     * 
+     * @return the instance's hash code 
+     */
+    public int hashCode()
+    {
+        int h = super.hashCode();
+        
+        if ( attributeType != null )
+        {
+            h = h*17 + attributeType.hashCode();
+        }
+        
+        return h;
+    }
+    
+    
+    /**
      * @see Object#toString()
      * 
      * @return A String representation of this instance