directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From elecha...@apache.org
Subject svn commit: r801340 [2/13] - in /directory/apacheds/trunk: core-entry/src/main/java/org/apache/directory/server/core/entry/ core-entry/src/test/java/org/apache/directory/server/core/entry/ core-integ/src/main/java/org/apache/directory/server/core/integ...
Date Wed, 05 Aug 2009 17:55:16 GMT

Modified: directory/apacheds/trunk/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerAttribute.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerAttribute.java?rev=801340&r1=801339&r2=801340&view=diff
==============================================================================
--- directory/apacheds/trunk/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerAttribute.java (original)
+++ directory/apacheds/trunk/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerAttribute.java Wed Aug  5 17:55:15 2009
@@ -1,1423 +1,1423 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-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;
-
-import org.apache.directory.shared.asn1.primitives.OID;
-import org.apache.directory.shared.ldap.entry.EntryAttribute;
-import org.apache.directory.shared.ldap.entry.Value;
-import org.apache.directory.shared.ldap.entry.client.ClientBinaryValue;
-import org.apache.directory.shared.ldap.entry.client.ClientStringValue;
-import org.apache.directory.shared.ldap.entry.client.DefaultClientAttribute;
-import org.apache.directory.shared.ldap.schema.AttributeType;
-import org.apache.directory.shared.ldap.util.StringTools;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
-/**
- * A server side entry attribute aware of schema.
- *
- * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- * @version $Rev$, $Date$
- */
-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 );
-    
-    /** The associated AttributeType */
-    private AttributeType attributeType;
-    
-    
-    //-----------------------------------------------------------------------
-    // utility methods
-    //-----------------------------------------------------------------------
-    /**
-     * Private helper method used to set an UpId from an attributeType
-     * 
-     * @param at The attributeType for which we want the upID
-     * @return the ID of the given attributeType
-     */
-    private String getUpId( AttributeType at )
-    {
-        String atUpId = at.getName();
-        
-        if ( atUpId == null )
-        {
-            atUpId = at.getOid();
-        }
-        
-        return atUpId;
-    }
-    
-    
-    //-------------------------------------------------------------------------
-    // Constructors
-    //-------------------------------------------------------------------------
-    /**
-     * 
-     * 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 attributeType The attribute's type 
-     * @param attribute The attribute to be copied
-     */
-    public DefaultServerAttribute( AttributeType attributeType, EntryAttribute attribute )
-    {
-        // 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 )
-        {
-            isHR = attribute.isHR();
-
-            // Copy all the values
-            for ( Value<?> value:attribute )
-            {
-                add( value.clone() );
-            }
-        }
-        else
-        {
-            
-            try
-            {
-                isHR = attributeType.getSyntax().isHumanReadable();
-            }
-            catch ( NamingException ne )
-            {
-                // 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 ( isHR )
-                    {
-                        serverValue = new ServerStringValue( attributeType, clientValue.getString() );
-                    }
-                    else
-                    {
-                        // We have to convert the value to a binary value first
-                        serverValue = new ServerBinaryValue( attributeType, 
-                            clientValue.getBytes() );
-                    }
-                }
-                else if ( clientValue instanceof ClientBinaryValue )
-                {
-                    if ( isHR )
-                    {
-                        // We have to convert the value to a String value first
-                        serverValue = new ServerStringValue( attributeType, 
-                            clientValue.getString() );
-                    }
-                    else
-                    {
-                        serverValue = new ServerBinaryValue( attributeType, clientValue.getBytes() );
-                    }
-                }
-
-                add( serverValue );
-            }
-        }
-    }
-    
-    
-    // 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 )
-        {
-            throw new IllegalArgumentException( "The AttributeType parameter should not be null" );
-        }
-        
-        setAttributeType( attributeType );
-        setUpId( upId, attributeType );
-        add( vals );
-    }
-
-
-    /**
-     * Create a new instance of a EntryAttribute, without ID but with some values.
-     * 
-     * @param attributeType The attributeType added on creation
-     * @param vals The added value for this attribute
-     */
-    public DefaultServerAttribute( AttributeType attributeType, String... vals )
-    {
-        this( null, attributeType, vals );
-    }
-
-
-    /**
-     * Create a new instance of a EntryAttribute.
-     * 
-     * @param upId the ID for the added attribute
-     * @param attributeType The attributeType added on creation
-     * @param vals the added values for this attribute
-     */
-    public DefaultServerAttribute( String upId, AttributeType attributeType, String... vals )
-    {
-        if ( attributeType == null )
-        {
-            throw new IllegalArgumentException( "The AttributeType parameter should not be null" );
-        }
-
-        setAttributeType( attributeType );
-        add( vals );
-        setUpId( upId, attributeType );
-    }
-
-
-    /**
-     * Create a new instance of a EntryAttribute, with some byte[] values.
-     * 
-     * @param attributeType The attributeType added on creation
-     * @param vals The value for the added attribute
-     */
-    public DefaultServerAttribute( AttributeType attributeType, byte[]... vals )
-    {
-        this( null, attributeType, vals );
-    }
-
-
-    /**
-     * Create a new instance of a EntryAttribute, with some byte[] values.
-     * 
-     * @param upId the ID for the added attribute
-     * @param attributeType the AttributeType to be added
-     * @param vals the values for the added attribute
-     */
-    public DefaultServerAttribute( String upId, AttributeType attributeType, byte[]... vals )
-    {
-        if ( attributeType == null )
-        {
-            throw new IllegalArgumentException( "The AttributeType parameter should not be null" );
-        }
-
-        setAttributeType( attributeType );
-        add( vals );
-        setUpId( upId, attributeType );
-    }
-    
-    
-    //-------------------------------------------------------------------------
-    // API
-    //-------------------------------------------------------------------------
-    /**
-     * <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>
-     * <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 int add( byte[]... vals )
-    {
-        if ( !isHR )
-        {
-            int nbAdded = 0;
-            
-            for ( byte[] val:vals )
-            {
-                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;
-        }
-    }    
-
-
-    /**
-     * <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 )
-            {
-                Value<String> newValue = new ServerStringValue( attributeType, val );
-                
-                if ( !contains( newValue ) )
-                {
-                    if ( add( newValue ) != 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;
-        }
-    }    
-
-
-    /**
-     * @see EntryAttribute#add(org.apache.directory.shared.ldap.entry.Value...)
-     * 
-     * @return the number of added values into this attribute
-     */
-    public int add( Value<?>... vals )
-    {
-        int nbAdded = 0;
-        
-        for ( Value<?> val:vals )
-        {
-            try
-            {
-                if ( attributeType.getSyntax().isHumanReadable() )
-                {
-                    if ( ( val == null ) || val.isNull() )
-                    {
-                        Value<String> nullSV = new ServerStringValue( attributeType, (String)null );
-                        
-                        if ( !values.contains( nullSV ) )
-                        {
-                            values.add( nullSV );
-                            nbAdded++;
-                        }
-                    }
-                    else if ( val instanceof ServerStringValue )
-                    {
-                        if ( !values.contains( val ) )
-                        {
-                            if ( values.add( val ) )
-                            {
-                                nbAdded++;
-                            }
-                        }
-                    }
-                    else if ( val instanceof ClientStringValue )
-                    {
-                        // If we get a Client value, convert it to a Server value first 
-                        Value<String> serverStringValue = new ServerStringValue( attributeType, val.getString() ); 
-                        
-                        if ( !values.contains( serverStringValue ) )
-                        {
-                            if ( values.add( serverStringValue ) )
-                            {
-                                nbAdded++;
-                            }
-                        }
-                    }
-                    else
-                    {
-                        String message = "The value must be a String, as its AttributeType is H/R";
-                        LOG.error( message );
-                    }
-                }
-                else
-                {
-                    if ( val == null )
-                    {
-                        Value<byte[]> nullSV = new ServerBinaryValue( attributeType, (byte[])null );
-                        
-                        if ( !values.contains( nullSV ) )
-                        {
-                            values.add( nullSV );
-                            nbAdded++;
-                        }
-                    }
-                    else if ( ( val instanceof ClientBinaryValue ) )
-                    {
-                        Value<byte[]> serverBinaryValue = new ServerBinaryValue( attributeType, val.getBytes() ); 
-                        
-                        if ( !values.contains( serverBinaryValue ) )
-                        {
-                            if ( values.add( serverBinaryValue ) )
-                            {
-                                nbAdded++;
-                            }
-                        }
-                    }
-                    else if ( val instanceof ServerBinaryValue )
-                    {
-                        if ( !values.contains( val ) )
-                        {
-                            if ( values.add( val ) )
-                            {
-                                nbAdded++;
-                            }
-                        }
-                    }
-                    else
-                    {
-                        String message = "The value must be a byte[], as its AttributeType is not H/R";
-                        LOG.error( message );
-                    }
-                }
-            }
-            catch ( NamingException ne )
-            {
-                String message = "Error while adding value '" + val.toString() +"' : " + ne.getMessage();
-                LOG.error( message );
-            }
-        }
-        
-        return nbAdded;
-    }
-
-
-    /**
-     * Remove all the values from this attribute type, including a 
-     * null value. 
-     */
-    public void clear()
-    {
-        values.clear();
-    }
-
-
-    /**
-     * <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
-     */
-    public boolean contains( byte[]... vals )
-    {
-        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 );
-                
-                try
-                {
-                    value.normalize();
-                }
-                catch ( NamingException ne )
-                {
-                    return false;
-                }
-                
-                if ( !values.contains( value ) )
-                {
-                    return false;
-                }
-            }
-            
-            return true;
-        }
-        else
-        {
-            return false;
-        }
-    }
-    
-    
-    /**
-     * <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>
-     *
-     * @param vals the values
-     * @return true if this attribute contains all the values, otherwise false
-     */
-    public boolean contains( String... vals )
-    {
-        if ( isHR )
-        {
-            // Iterate through all the values, and quit if we 
-            // don't find one in the values
-            for ( String val:vals )
-            {
-                ServerStringValue value = new ServerStringValue( attributeType, val );
-                
-                if ( !values.contains( value ) )
-                {
-                    return false;
-                }
-            }
-            
-            return true;
-        }
-        else
-        {
-            return false;
-        }
-    }
-    
-    
-    /**
-     * <p>
-     * Indicates whether the specified values are some of the attribute's values.
-     * </p>
-     * <p>
-     * If the Attribute is HR, te metho will only accept String Values. Otherwise, 
-     * it will only accept Binary values.
-     * </p>
-     *
-     * @param vals the values
-     * @return true if this attribute contains all the values, otherwise false
-     */
-    public boolean contains( Value<?>... vals )
-    {
-        // Iterate through all the values, and quit if we 
-        // don't find one in the values. We have to separate the check
-        // depending on the isHR flag value.
-        if ( isHR )
-        {
-            for ( Value<?> val:vals )
-            {
-                if ( val instanceof ServerStringValue )
-                {
-                    if ( !values.contains( val ) )
-                    {
-                        return false;
-                    }
-                }
-                else if ( val instanceof ClientStringValue )
-                {
-                    ServerStringValue serverValue = new ServerStringValue( attributeType, val.isNull() ? (String)null : val.getString() );
-                    
-                    if ( !values.contains( serverValue ) )
-                    {
-                        return false;
-                    }
-                }
-                else
-                {
-                    // Not a String value
-                    return false;
-                }
-            }
-        }
-        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
-            {
-                // 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 );
-                }
-            }
-        }
-    }
-
-
-    /**
-     * Convert the ServerAttribute to a ClientAttribute
-     *
-     * @return An instance of ClientAttribute
-     */
-    public EntryAttribute toClientAttribute()
-    {
-        // Create the new EntryAttribute
-        EntryAttribute clientAttribute = new DefaultClientAttribute( upId );
-        
-        // Copy the values
-        for ( Value<?> value:this )
-        {
-            Value<?> clientValue = null;
-            
-            if ( value instanceof ServerStringValue )
-            {
-                clientValue = new ClientStringValue( value.getString() );
-            }
-            else
-            {
-                clientValue = new ClientBinaryValue( value.getBytes() );
-            }
-            
-            clientAttribute.add( clientValue );
-        }
-        
-        return clientAttribute;
-    }
-
-
-    //-------------------------------------------------------------------------
-    // Serialization methods
-    //-------------------------------------------------------------------------
-    
-    /**
-     * @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 void writeExternal( ObjectOutput out ) throws IOException
-    {
-        throw new IllegalStateException( "Cannot use standard serialization for a ServerAttribute" );
-    }
-    
-    
-    /**
-     * @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
-     * 
-     */
-    public void serialize( ObjectOutput out ) throws IOException
-    {
-        // Write the UPId (the id will be deduced from the upID)
-        out.writeUTF( upId );
-        
-        // Write the HR flag, if not null
-        if ( isHR != null )
-        {
-            out.writeBoolean( true );
-            out.writeBoolean( isHR );
-        }
-        else
-        {
-            out.writeBoolean( false );
-        }
-        
-        // Write the number of values
-        out.writeInt( size() );
-        
-        if ( size() > 0 ) 
-        {
-            // Write each value
-            for ( Value<?> value:values )
-            {
-                // Write the value, using the correct method
-                if ( value instanceof ServerStringValue )
-                {
-                    ((ServerStringValue)value).serialize( out );
-                }
-                else
-                {
-                    ((ServerBinaryValue)value).serialize( out );
-                }
-            }
-        }
-    }
-
-    
-    /**
-     * @see java.io.Externalizable#readExternal(ObjectInput)
-     * 
-     * We can't use this method for a ServerAttribute, as we have to feed the value
-     * with an AttributeType object
-     */
-    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
-    {
-        throw new IllegalStateException( "Cannot use standard serialization for a ServerAttribute" );
-    }
-    
-    
-    /**
-     * @see Externalizable#readExternal(ObjectInput)
-     */
-    public void deserialize( ObjectInput in ) throws IOException, ClassNotFoundException
-    {
-        // Read the ID and the UPId
-        upId = in.readUTF();
-        
-        // Compute the id
-        setUpId( upId );
-        
-        // Read the HR flag, if not null
-        if ( in.readBoolean() )
-        {
-            isHR = in.readBoolean();
-        }
-
-        // 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 class methods
-    //-------------------------------------------------------------------------
-    /**
-     * 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;
-    }
-
-
-    /**
-     * @see Object#equals(Object)
-     * 
-     * @return <code>true</code> if the two objects are equal
-     */
-    public boolean equals( Object obj )
-    {
-        if ( obj == this )
-        {
-            return true;
-        }
-        
-        if ( ! (obj instanceof ServerAttribute ) )
-        {
-            return false;
-        }
-        
-        ServerAttribute other = (ServerAttribute)obj;
-        
-        if ( !attributeType.equals( other.getAttributeType() ) )
-        {
-            return false;
-        }
-        
-        if ( values.size() != other.size() )
-        {
-            return false;
-        }
-        
-        for ( Value<?> val:values )
-        {
-            if ( ! other.contains( val ) )
-            {
-                return false;
-            }
-        }
-        
-        return true;
-    }
-    
-    
-    /**
-     * 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
-     */
-    public String toString()
-    {
-        StringBuilder sb = new StringBuilder();
-        
-        if ( ( values != null ) && ( values.size() != 0 ) )
-        {
-            for ( Value<?> value:values )
-            {
-                sb.append( "    " ).append( upId ).append( ": " );
-                
-                if ( value.isNull() )
-                {
-                    sb.append( "''" );
-                }
-                else
-                {
-                    sb.append( value );
-                }
-                
-                sb.append( '\n' );
-            }
-        }
-        else
-        {
-            sb.append( "    " ).append( upId ).append( ": (null)\n" );
-        }
-        
-        return sb.toString();
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+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;
+
+import org.apache.directory.shared.asn1.primitives.OID;
+import org.apache.directory.shared.ldap.entry.EntryAttribute;
+import org.apache.directory.shared.ldap.entry.Value;
+import org.apache.directory.shared.ldap.entry.client.ClientBinaryValue;
+import org.apache.directory.shared.ldap.entry.client.ClientStringValue;
+import org.apache.directory.shared.ldap.entry.client.DefaultClientAttribute;
+import org.apache.directory.shared.ldap.schema.AttributeType;
+import org.apache.directory.shared.ldap.util.StringTools;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A server side entry attribute aware of schema.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+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 );
+    
+    /** The associated AttributeType */
+    private AttributeType attributeType;
+    
+    
+    //-----------------------------------------------------------------------
+    // utility methods
+    //-----------------------------------------------------------------------
+    /**
+     * Private helper method used to set an UpId from an attributeType
+     * 
+     * @param at The attributeType for which we want the upID
+     * @return the ID of the given attributeType
+     */
+    private String getUpId( AttributeType at )
+    {
+        String atUpId = at.getName();
+        
+        if ( atUpId == null )
+        {
+            atUpId = at.getOid();
+        }
+        
+        return atUpId;
+    }
+    
+    
+    //-------------------------------------------------------------------------
+    // Constructors
+    //-------------------------------------------------------------------------
+    /**
+     * 
+     * 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 attributeType The attribute's type 
+     * @param attribute The attribute to be copied
+     */
+    public DefaultServerAttribute( AttributeType attributeType, EntryAttribute attribute )
+    {
+        // 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 )
+        {
+            isHR = attribute.isHR();
+
+            // Copy all the values
+            for ( Value<?> value:attribute )
+            {
+                add( value.clone() );
+            }
+        }
+        else
+        {
+            
+            try
+            {
+                isHR = attributeType.getSyntax().isHumanReadable();
+            }
+            catch ( NamingException ne )
+            {
+                // 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 ( isHR )
+                    {
+                        serverValue = new ServerStringValue( attributeType, clientValue.getString() );
+                    }
+                    else
+                    {
+                        // We have to convert the value to a binary value first
+                        serverValue = new ServerBinaryValue( attributeType, 
+                            clientValue.getBytes() );
+                    }
+                }
+                else if ( clientValue instanceof ClientBinaryValue )
+                {
+                    if ( isHR )
+                    {
+                        // We have to convert the value to a String value first
+                        serverValue = new ServerStringValue( attributeType, 
+                            clientValue.getString() );
+                    }
+                    else
+                    {
+                        serverValue = new ServerBinaryValue( attributeType, clientValue.getBytes() );
+                    }
+                }
+
+                add( serverValue );
+            }
+        }
+    }
+    
+    
+    // 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 )
+        {
+            throw new IllegalArgumentException( "The AttributeType parameter should not be null" );
+        }
+        
+        setAttributeType( attributeType );
+        setUpId( upId, attributeType );
+        add( vals );
+    }
+
+
+    /**
+     * Create a new instance of a EntryAttribute, without ID but with some values.
+     * 
+     * @param attributeType The attributeType added on creation
+     * @param vals The added value for this attribute
+     */
+    public DefaultServerAttribute( AttributeType attributeType, String... vals )
+    {
+        this( null, attributeType, vals );
+    }
+
+
+    /**
+     * Create a new instance of a EntryAttribute.
+     * 
+     * @param upId the ID for the added attribute
+     * @param attributeType The attributeType added on creation
+     * @param vals the added values for this attribute
+     */
+    public DefaultServerAttribute( String upId, AttributeType attributeType, String... vals )
+    {
+        if ( attributeType == null )
+        {
+            throw new IllegalArgumentException( "The AttributeType parameter should not be null" );
+        }
+
+        setAttributeType( attributeType );
+        add( vals );
+        setUpId( upId, attributeType );
+    }
+
+
+    /**
+     * Create a new instance of a EntryAttribute, with some byte[] values.
+     * 
+     * @param attributeType The attributeType added on creation
+     * @param vals The value for the added attribute
+     */
+    public DefaultServerAttribute( AttributeType attributeType, byte[]... vals )
+    {
+        this( null, attributeType, vals );
+    }
+
+
+    /**
+     * Create a new instance of a EntryAttribute, with some byte[] values.
+     * 
+     * @param upId the ID for the added attribute
+     * @param attributeType the AttributeType to be added
+     * @param vals the values for the added attribute
+     */
+    public DefaultServerAttribute( String upId, AttributeType attributeType, byte[]... vals )
+    {
+        if ( attributeType == null )
+        {
+            throw new IllegalArgumentException( "The AttributeType parameter should not be null" );
+        }
+
+        setAttributeType( attributeType );
+        add( vals );
+        setUpId( upId, attributeType );
+    }
+    
+    
+    //-------------------------------------------------------------------------
+    // API
+    //-------------------------------------------------------------------------
+    /**
+     * <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>
+     * <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 int add( byte[]... vals )
+    {
+        if ( !isHR )
+        {
+            int nbAdded = 0;
+            
+            for ( byte[] val:vals )
+            {
+                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;
+        }
+    }    
+
+
+    /**
+     * <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 )
+            {
+                Value<String> newValue = new ServerStringValue( attributeType, val );
+                
+                if ( !contains( newValue ) )
+                {
+                    if ( add( newValue ) != 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;
+        }
+    }    
+
+
+    /**
+     * @see EntryAttribute#add(org.apache.directory.shared.ldap.entry.Value...)
+     * 
+     * @return the number of added values into this attribute
+     */
+    public int add( Value<?>... vals )
+    {
+        int nbAdded = 0;
+        
+        for ( Value<?> val:vals )
+        {
+            try
+            {
+                if ( attributeType.getSyntax().isHumanReadable() )
+                {
+                    if ( ( val == null ) || val.isNull() )
+                    {
+                        Value<String> nullSV = new ServerStringValue( attributeType, (String)null );
+                        
+                        if ( !values.contains( nullSV ) )
+                        {
+                            values.add( nullSV );
+                            nbAdded++;
+                        }
+                    }
+                    else if ( val instanceof ServerStringValue )
+                    {
+                        if ( !values.contains( val ) )
+                        {
+                            if ( values.add( val ) )
+                            {
+                                nbAdded++;
+                            }
+                        }
+                    }
+                    else if ( val instanceof ClientStringValue )
+                    {
+                        // If we get a Client value, convert it to a Server value first 
+                        Value<String> serverStringValue = new ServerStringValue( attributeType, val.getString() ); 
+                        
+                        if ( !values.contains( serverStringValue ) )
+                        {
+                            if ( values.add( serverStringValue ) )
+                            {
+                                nbAdded++;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        String message = "The value must be a String, as its AttributeType is H/R";
+                        LOG.error( message );
+                    }
+                }
+                else
+                {
+                    if ( val == null )
+                    {
+                        Value<byte[]> nullSV = new ServerBinaryValue( attributeType, (byte[])null );
+                        
+                        if ( !values.contains( nullSV ) )
+                        {
+                            values.add( nullSV );
+                            nbAdded++;
+                        }
+                    }
+                    else if ( ( val instanceof ClientBinaryValue ) )
+                    {
+                        Value<byte[]> serverBinaryValue = new ServerBinaryValue( attributeType, val.getBytes() ); 
+                        
+                        if ( !values.contains( serverBinaryValue ) )
+                        {
+                            if ( values.add( serverBinaryValue ) )
+                            {
+                                nbAdded++;
+                            }
+                        }
+                    }
+                    else if ( val instanceof ServerBinaryValue )
+                    {
+                        if ( !values.contains( val ) )
+                        {
+                            if ( values.add( val ) )
+                            {
+                                nbAdded++;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        String message = "The value must be a byte[], as its AttributeType is not H/R";
+                        LOG.error( message );
+                    }
+                }
+            }
+            catch ( NamingException ne )
+            {
+                String message = "Error while adding value '" + val.toString() +"' : " + ne.getMessage();
+                LOG.error( message );
+            }
+        }
+        
+        return nbAdded;
+    }
+
+
+    /**
+     * Remove all the values from this attribute type, including a 
+     * null value. 
+     */
+    public void clear()
+    {
+        values.clear();
+    }
+
+
+    /**
+     * <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
+     */
+    public boolean contains( byte[]... vals )
+    {
+        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 );
+                
+                try
+                {
+                    value.normalize();
+                }
+                catch ( NamingException ne )
+                {
+                    return false;
+                }
+                
+                if ( !values.contains( value ) )
+                {
+                    return false;
+                }
+            }
+            
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+    
+    
+    /**
+     * <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>
+     *
+     * @param vals the values
+     * @return true if this attribute contains all the values, otherwise false
+     */
+    public boolean contains( String... vals )
+    {
+        if ( isHR )
+        {
+            // Iterate through all the values, and quit if we 
+            // don't find one in the values
+            for ( String val:vals )
+            {
+                ServerStringValue value = new ServerStringValue( attributeType, val );
+                
+                if ( !values.contains( value ) )
+                {
+                    return false;
+                }
+            }
+            
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+    
+    
+    /**
+     * <p>
+     * Indicates whether the specified values are some of the attribute's values.
+     * </p>
+     * <p>
+     * If the Attribute is HR, te metho will only accept String Values. Otherwise, 
+     * it will only accept Binary values.
+     * </p>
+     *
+     * @param vals the values
+     * @return true if this attribute contains all the values, otherwise false
+     */
+    public boolean contains( Value<?>... vals )
+    {
+        // Iterate through all the values, and quit if we 
+        // don't find one in the values. We have to separate the check
+        // depending on the isHR flag value.
+        if ( isHR )
+        {
+            for ( Value<?> val:vals )
+            {
+                if ( val instanceof ServerStringValue )
+                {
+                    if ( !values.contains( val ) )
+                    {
+                        return false;
+                    }
+                }
+                else if ( val instanceof ClientStringValue )
+                {
+                    ServerStringValue serverValue = new ServerStringValue( attributeType, val.isNull() ? (String)null : val.getString() );
+                    
+                    if ( !values.contains( serverValue ) )
+                    {
+                        return false;
+                    }
+                }
+                else
+                {
+                    // Not a String value
+                    return false;
+                }
+            }
+        }
+        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
+            {
+                // 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 );
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Convert the ServerAttribute to a ClientAttribute
+     *
+     * @return An instance of ClientAttribute
+     */
+    public EntryAttribute toClientAttribute()
+    {
+        // Create the new EntryAttribute
+        EntryAttribute clientAttribute = new DefaultClientAttribute( upId );
+        
+        // Copy the values
+        for ( Value<?> value:this )
+        {
+            Value<?> clientValue = null;
+            
+            if ( value instanceof ServerStringValue )
+            {
+                clientValue = new ClientStringValue( value.getString() );
+            }
+            else
+            {
+                clientValue = new ClientBinaryValue( value.getBytes() );
+            }
+            
+            clientAttribute.add( clientValue );
+        }
+        
+        return clientAttribute;
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Serialization methods
+    //-------------------------------------------------------------------------
+    
+    /**
+     * @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 void writeExternal( ObjectOutput out ) throws IOException
+    {
+        throw new IllegalStateException( "Cannot use standard serialization for a ServerAttribute" );
+    }
+    
+    
+    /**
+     * @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
+     * 
+     */
+    public void serialize( ObjectOutput out ) throws IOException
+    {
+        // Write the UPId (the id will be deduced from the upID)
+        out.writeUTF( upId );
+        
+        // Write the HR flag, if not null
+        if ( isHR != null )
+        {
+            out.writeBoolean( true );
+            out.writeBoolean( isHR );
+        }
+        else
+        {
+            out.writeBoolean( false );
+        }
+        
+        // Write the number of values
+        out.writeInt( size() );
+        
+        if ( size() > 0 ) 
+        {
+            // Write each value
+            for ( Value<?> value:values )
+            {
+                // Write the value, using the correct method
+                if ( value instanceof ServerStringValue )
+                {
+                    ((ServerStringValue)value).serialize( out );
+                }
+                else
+                {
+                    ((ServerBinaryValue)value).serialize( out );
+                }
+            }
+        }
+    }
+
+    
+    /**
+     * @see java.io.Externalizable#readExternal(ObjectInput)
+     * 
+     * We can't use this method for a ServerAttribute, as we have to feed the value
+     * with an AttributeType object
+     */
+    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        throw new IllegalStateException( "Cannot use standard serialization for a ServerAttribute" );
+    }
+    
+    
+    /**
+     * @see Externalizable#readExternal(ObjectInput)
+     */
+    public void deserialize( ObjectInput in ) throws IOException, ClassNotFoundException
+    {
+        // Read the ID and the UPId
+        upId = in.readUTF();
+        
+        // Compute the id
+        setUpId( upId );

[... 160 lines stripped ...]


Mime
View raw message