You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ak...@apache.org on 2008/03/18 06:07:29 UTC

svn commit: r638218 [2/4] - in /directory/sandbox/akarasulu/bigbang/shared: ./ asn1-codec/ asn1-codec/src/main/resources/META-INF/ asn1-codec/src/site/ asn1/ asn1/src/main/resources/META-INF/ asn1/src/site/ convert/ convert/src/main/java/org/apache/dir...

Modified: directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/ClientStringValue.java
URL: http://svn.apache.org/viewvc/directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/ClientStringValue.java?rev=638218&r1=638217&r2=638218&view=diff
==============================================================================
--- directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/ClientStringValue.java (original)
+++ directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/ClientStringValue.java Mon Mar 17 22:07:20 2008
@@ -20,7 +20,9 @@
 
 
 import org.apache.directory.shared.ldap.NotImplementedException;
-import org.apache.directory.shared.ldap.entry.AbstractStringValue;
+import org.apache.directory.shared.ldap.entry.AbstractValue;
+import org.apache.directory.shared.ldap.entry.Value;
+import org.apache.directory.shared.ldap.schema.Normalizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,26 +38,26 @@
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  * @version $Rev$, $Date$
  */
-public class ClientStringValue extends AbstractStringValue implements ClientValue<String>
+public class ClientStringValue extends AbstractValue<String>
 {
     /** Used for serialization */
     public static final long serialVersionUID = 2L;
     
+    
     /** logger for reporting errors that might not be handled properly upstream */
     private static final Logger LOG = LoggerFactory.getLogger( ClientStringValue.class );
 
-    /** the canonical representation of the wrapped String value */
-    private transient String normalizedValue;
-
-    /** cached results of the isValid() method call */
-    private transient Boolean valid;
-
-
+    
+    // -----------------------------------------------------------------------
+    // Constructors
+    // -----------------------------------------------------------------------
     /**
      * Creates a ServerStringValue without an initial wrapped value.
      */
     public ClientStringValue()
     {
+        normalized = false;
+        valid = null;
     }
 
 
@@ -66,16 +68,40 @@
      */
     public ClientStringValue( String wrapped )
     {
-        super.set( wrapped );
+        this.wrapped = wrapped;
+        normalized = false;
+        valid = null;
     }
 
 
     // -----------------------------------------------------------------------
     // Value<String> Methods
     // -----------------------------------------------------------------------
+    /**
+     * Get the stored value.
+     *
+     * @return The stored value
+     */
+    public String get()
+    {
+        return wrapped;
+    }
 
 
     /**
+     * Get a copy of the stored value.
+     *
+     * @return A copy of the stored value.
+     */
+    public String getCopy()
+    {
+        // The String is immutable, we can safely return the internal
+        // object without copying it.
+        return wrapped;
+    }
+    
+    
+    /**
      * Sets the wrapped String value.  Has the side effect of setting the
      * normalizedValue and the valid flags to null if the wrapped value is
      * different than what is already set.  These cached values must be
@@ -87,34 +113,29 @@
     {
         // Why should we invalidate the normalized value if it's we're setting the
         // wrapper to it's current value?
-        if ( wrapped.equals( get() ) )
+        if ( ( wrapped != null ) && wrapped.equals( get() ) )
         {
             return;
         }
 
         normalizedValue = null;
+        normalized = false;
         valid = null;
-        super.set( wrapped );
+        this.wrapped = wrapped;
     }
 
 
-    // -----------------------------------------------------------------------
-    // ServerValue<String> Methods
-    // -----------------------------------------------------------------------
-
-
     /**
-     * Gets the normalized (cannonical) representation for the wrapped string.
+     * Gets the normalized (canonical) representation for the wrapped string.
      * If the wrapped String is null, null is returned, otherwise the normalized
-     * form is returned.  If no the normalizedValue is null, then this method
+     * form is returned.  If the normalizedValue is null, then this method
      * will attempt to generate it from the wrapped value: repeated calls to
      * this method do not unnecessarily normalize the wrapped value.  Only changes
      * to the wrapped value result in attempts to normalize the wrapped value.
      *
      * @return gets the normalized value
-     * @throws NamingException if the value cannot be properly normalized
      */
-    public String getNormalized() throws NamingException
+    public String getNormalizedValue()
     {
         if ( isNull() )
         {
@@ -123,6 +144,7 @@
 
         if ( normalizedValue == null )
         {
+            return wrapped;
         }
 
         return normalizedValue;
@@ -130,31 +152,45 @@
 
 
     /**
-     * Uses the syntaxChecker associated with the attributeType to check if the
-     * value is valid.  Repeated calls to this method do not attempt to re-check
-     * the syntax of the wrapped value every time if the wrapped value does not
-     * change. Syntax checks only result on the first check, and when the wrapped
-     * value changes.
+     * Gets a copy of the the normalized (canonical) representation 
+     * for the wrapped value.
      *
-     * @see ServerValue#isValid()
+     * @return gets a copy of the normalized value
+     */
+    public String getNormalizedValueCopy()
+    {
+        return getNormalizedValue();
+    }
+
+
+    /**
+     * Normalize the value. For a client String value, applies the given normalizer.
+     * 
+     * It supposes that the client has access to the schema in order to select the
+     * appropriate normalizer.
+     * 
+     * @param Normalizer The normalizer to apply to the value
+     * @exception NamingException If the value cannot be normalized
      */
-    public final boolean isValid() throws NamingException
+    public final void normalize( Normalizer normalizer ) throws NamingException
     {
-        if ( valid != null )
+        if ( normalizer != null )
         {
-            return valid;
+            normalizedValue = (String)normalizer.normalize( wrapped );
+            normalized = true;
         }
-
-        return valid;
     }
 
-
+    
+    // -----------------------------------------------------------------------
+    // Comparable<String> Methods
+    // -----------------------------------------------------------------------
     /**
      * @see ServerValue#compareTo(ServerValue)
      * @throws IllegalStateException on failures to extract the comparator, or the
      * normalizers needed to perform the required comparisons based on the schema
      */
-    public int compareTo( ClientValue<String> value )
+    public int compareTo( Value<String> value )
     {
         if ( isNull() )
         {
@@ -175,17 +211,35 @@
         if ( value instanceof ClientStringValue )
         {
             ClientStringValue stringValue = ( ClientStringValue ) value;
+            
+            return getNormalizedValue().compareTo( stringValue.getNormalizedValue() );
+        }
+        else 
+        {
+            String message = "Cannot compare " + toString() + " with the unknown value " + value.getClass();
+            LOG.error( message );
+            throw new NotImplementedException( message );
         }
-
-        throw new NotImplementedException( "I don't know what to do if value is not a ServerStringValue" );
     }
 
 
     // -----------------------------------------------------------------------
-    // Object Methods
+    // Cloneable methods
     // -----------------------------------------------------------------------
+    /**
+     * Get a clone of the Client Value
+     * 
+     * @return a copy of the current value
+     */
+    public ClientStringValue clone()
+    {
+        return (ClientStringValue)super.clone();
+    }
 
 
+    // -----------------------------------------------------------------------
+    // Object Methods
+    // -----------------------------------------------------------------------
     /**
      * @see Object#hashCode()
      * @throws IllegalStateException on failures to extract the comparator, or the
@@ -200,26 +254,16 @@
             return 0;
         }
 
-        try
-        {
-            return getNormalized().hashCode();
-        }
-        catch ( NamingException e )
-        {
-            String msg = "Failed to normalize \"" + get() + "\" while trying to get hashCode()";
-            LOG.error( msg, e );
-            throw new IllegalStateException( msg, e );
-        }
+        // If the normalized value is null, will default to wrapped
+        // which cannot be null at this point.
+        return getNormalizedValue().hashCode();
     }
 
 
     /**
-     * Checks to see if this ServerStringValue equals the supplied object.
-     *
-     * This equals implementation overrides the StringValue implementation which
-     * is not schema aware.
-     * @throws IllegalStateException on failures to extract the comparator, or the
-     * normalizers needed to perform the required comparisons based on the schema
+     * @see Object#equals(Object)
+     * 
+     * Two ClientStringValue are equals if their normalized values are equal
      */
     public boolean equals( Object obj )
     {
@@ -235,46 +279,21 @@
 
         ClientStringValue other = ( ClientStringValue ) obj;
         
-        if ( isNull() && other.isNull() )
-        {
-            return true;
-        }
-
-        if ( isNull() != other.isNull() )
+        if ( this.isNull() )
         {
-            return false;
-        }
-
-        // now unlike regular values we have to compare the normalized values
-        try
-        {
-            return getNormalized().equals( other.getNormalized() );
-        }
-        catch ( NamingException e )
-        {
-            String msg = "Failed to normalize while testing for equality on String values: \"";
-            msg += get() + "\"" + " and \"" + other.get() + "\"" ;
-            LOG.error( msg, e );
-            throw new IllegalStateException( msg, e );
+            return other.isNull();
         }
+        
+        // Test the normalized values
+        return this.getNormalizedValue().equals( other.getNormalizedValue() );
     }
-
-
-    // -----------------------------------------------------------------------
-    // Private Helper Methods (might be put into abstract base class)
-    // -----------------------------------------------------------------------
+    
+    
     /**
-     * @return a copy of the current value
+     * @see Object#toString()
      */
-    public ClientStringValue clone()
+    public String toString()
     {
-        try
-        {
-            return (ClientStringValue)super.clone();
-        }
-        catch ( CloneNotSupportedException cnse )
-        {
-            return null;
-        }
+        return "'" + wrapped + "'";
     }
 }

Modified: directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/DefaultClientAttribute.java
URL: http://svn.apache.org/viewvc/directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/DefaultClientAttribute.java?rev=638218&r1=638217&r2=638218&view=diff
==============================================================================
--- directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/DefaultClientAttribute.java (original)
+++ directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/DefaultClientAttribute.java Mon Mar 17 22:07:20 2008
@@ -20,6 +20,9 @@
 
 
 import org.apache.directory.shared.ldap.entry.EntryAttribute;
+import org.apache.directory.shared.ldap.entry.Value;
+import org.apache.directory.shared.ldap.schema.syntax.SyntaxChecker;
+import org.apache.directory.shared.ldap.util.StringTools;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -27,15 +30,21 @@
 import javax.naming.directory.InvalidAttributeValueException;
 
 import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
 
 
 /**
- * A server side entry attribute aware of schema.
+ * A client side entry attribute. The client is not aware of the schema,
+ * so we can't tell if the stored value will be String or Binary. We will
+ * default to Binary.<p>
+ * To define the kind of data stored, the client must set the isHR flag.
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  * @version $Rev$, $Date$
  */
-public final class DefaultClientAttribute extends AbstractClientAttribute
+public class DefaultClientAttribute implements ClientAttribute
 {
     /** Used for serialization */
     public static final long serialVersionUID = 2L;
@@ -44,6 +53,20 @@
     private static final Logger LOG = LoggerFactory.getLogger( DefaultClientAttribute.class );
     
     
+    /** The set of contained values */
+    protected Set<Value<?>> values = new LinkedHashSet<Value<?>>();
+    
+    /** The User provided ID */
+    protected String upId;
+
+    /** The normalized ID */
+    protected String id;
+
+    /** Tells if the attribute is Human Readable or not. When not set, 
+     * this flag is null. */
+    protected Boolean isHR;
+
+
     // maybe have some additional convenience constructors which take
     // an initial value as a string or a byte[]
     /**
@@ -64,24 +87,6 @@
 
 
     /**
-     * Doc me more!
-     *
-     * If the value does not correspond to the same attributeType, then it's
-     * wrapped value is copied into a new ClientValue which uses the specified
-     * attributeType.
-     *
-     * @param vals an initial set of values for this attribute
-     * @throws NamingException if there are problems creating the new attribute
-     */
-    public DefaultClientAttribute( ClientValue<?>... vals ) throws NamingException
-    {
-        this( null, vals );
-    }
-
-
-    /**
-     * Doc me more!
-     *
      * If the value does not correspond to the same attributeType, then it's
      * wrapped value is copied into a new ClientValue which uses the specified
      * attributeType.
@@ -91,9 +96,8 @@
      * @param upId
      * @param attributeType the attribute type according to the schema
      * @param vals an initial set of values for this attribute
-     * @throws NamingException if there are problems creating the new attribute
      */
-    public DefaultClientAttribute( String upId, ClientValue<?>... vals ) throws NamingException
+    public DefaultClientAttribute( String upId, Value<?>... vals )
     {
         // The value can be null, this is a valid value.
         if ( vals[0] == null )
@@ -102,7 +106,7 @@
         }
         else
         {
-            for ( ClientValue<?> val:vals )
+            for ( Value<?> val:vals )
             {
                 if ( val instanceof ClientStringValue )
                 {
@@ -128,18 +132,19 @@
 
 
     /**
-     * Create a new instance of a EntryAttribute, without ID but with some values.
+     * Create a new instance of a EntryAttribute.
      */
-    public DefaultClientAttribute( String... vals ) throws NamingException
+    public DefaultClientAttribute( String upId, String... vals )
     {
-        this( null, vals );
+        add( vals );
+        setUpId( upId );
     }
 
 
     /**
-     * Create a new instance of a EntryAttribute.
+     * Create a new instance of a EntryAttribute, with some byte[] values.
      */
-    public DefaultClientAttribute( String upId, String... vals ) throws NamingException
+    public DefaultClientAttribute( String upId, byte[]... vals )
     {
         add( vals );
         setUpId( upId );
@@ -147,25 +152,111 @@
 
 
     /**
-     * Create a new instance of a EntryAttribute, with some byte[] values.
+     * <p>
+     * Get the byte[] value, if and only if the value is known to be Binary,
+     * otherwise a InvalidAttributeValueException will be thrown
+     * </p>
+     * <p>
+     * Note that this method returns the first value only.
+     * </p>
+     *
+     * @return The value as a byte[]
+     * @throws InvalidAttributeValueException If the value is a String
+     */
+    public byte[] getBytes() throws InvalidAttributeValueException
+    {
+        Value<?> value = get();
+        
+        if ( value instanceof ClientBinaryValue )
+        {
+            return (byte[])value.get();
+        }
+        else
+        {
+            String message = "The value is expected to be a byte[]";
+            LOG.error( message );
+            throw new InvalidAttributeValueException( message );
+        }
+    }
+
+
+    /**
+     * <p>
+     * Get the String value, if and only if the value is known to be a String,
+     * otherwise a InvalidAttributeValueException will be thrown
+     * </p>
+     * <p>
+     * Note that this method returns the first value only.
+     * </p>
+     *
+     * @return The value as a String
+     * @throws InvalidAttributeValueException If the value is a byte[]
      */
-    public DefaultClientAttribute( byte[]... vals ) throws NamingException
+    public String getString() throws InvalidAttributeValueException
     {
-        this( null, vals );
+        Value<?> value = get();
+        
+        if ( value instanceof ClientStringValue )
+        {
+            return (String)value.get();
+        }
+        else
+        {
+            String message = "The value is expected to be a String";
+            LOG.error( message );
+            throw new InvalidAttributeValueException( message );
+        }
     }
 
 
     /**
-     * Create a new instance of a EntryAttribute, with some byte[] values.
+     * Get's the attribute identifier. Its value is the same than the
+     * user provided ID.
+     *
+     * @return the attribute's identifier
      */
-    public DefaultClientAttribute( String upId, byte[]... vals ) throws NamingException
+    public String getId()
     {
-        add( vals );
-        setUpId( upId );
+        return id;
     }
 
 
     /**
+     * <p>
+     * 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 )
+    {
+        this.isHR = isHR;
+        //TODO : deal with the values, we may have to convert them.
+    }
+
+    
+    /**
+     * Set the normalized ID. The ID will be lowercased, and spaces
+     * will be trimmed. 
+     *
+     * @param id The attribute ID
+     * @throws IllegalArgumentException If the ID is empty or null or
+     * resolve to an empty value after being trimmed
+     */
+    public void setId( String id )
+    {
+        this.id = StringTools.trim( StringTools.lowerCaseAscii( id ) );
+
+        if ( this.id.length() == 0 )
+        {
+            this.id = null;
+            throw new IllegalArgumentException( "An ID cannnot be null, empty, or resolved to an emtpy" +
+                " value when trimmed" );
+        }
+    }
+
+    
+    /**
      * Get's the user provided identifier for this entry.  This is the value
      * that will be used as the identifier for the attribute within the
      * entry.  If this is a commonName attribute for example and the user
@@ -183,6 +274,44 @@
 
 
     /**
+     * Set the user provided ID. It will also set the ID, normalizing
+     * the upId (removing spaces before and after, and lowercasing it)
+     *
+     * @param upId The attribute ID
+     * @throws IllegalArgumentException If the ID is empty or null or
+     * resolve to an empty value after being trimmed
+     */
+    public void setUpId( String upId )
+    {
+        this.upId = StringTools.trim( upId );
+        
+        if ( this.upId.length() == 0 )
+        {
+            this.upId = null;
+            throw new IllegalArgumentException( "An ID cannnot be null, empty, or resolved to an emtpy" +
+                " value when trimmed" );
+        }
+
+        this.id = StringTools.lowerCaseAscii( this.upId );
+    }
+
+
+    /**
+     * <p>
+     * Tells if the attribute is Human Readable. 
+     * </p>
+     * <p>This flag is set by the caller, or implicitly when adding String 
+     * values into an attribute which is not yet declared as Binary.
+     * </p> 
+     * @return
+     */
+    public boolean isHR()
+    {
+        return isHR != null ? isHR : false; 
+    }
+
+    
+    /**
      * Checks to see if this attribute is valid along with the values it contains.
      *
      * @return true if the attribute and it's values are valid, false otherwise
@@ -190,9 +319,9 @@
      */
     public boolean isValid() throws NamingException
     {
-        for ( ClientValue<?> value : values )
+        for ( Value<?> value:values )
         {
-            if ( ! value.isValid() )
+            if ( !value.isValid() )
             {
                 return false;
             }
@@ -203,74 +332,233 @@
 
 
     /**
-     * @see EntryAttribute#add(org.apache.directory.shared.ldap.entry.Value)
+     * Checks to see if this attribute is valid along with the values it contains.
+     *
+     * @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 add( ClientValue<?> val ) throws InvalidAttributeValueException, NamingException
+    public boolean isValid( SyntaxChecker checker ) throws NamingException
     {
-        if ( val == null )
+        for ( Value<?> value : values )
         {
-            ClientValue<String> nullSV = new ClientStringValue( (String)null );
-            
-            if ( values.contains( nullSV ) )
+            if ( !value.isValid( checker ) )
             {
                 return false;
             }
-            else
-            {
-                values.add( nullSV );
-                return true;
-            }
         }
 
-        if ( values.contains( val ) )
-        {
-            return false;
-        }
-        
-        return values.add( val );
+        return true;
     }
 
 
     /**
-     * @see EntryAttribute#add(org.apache.directory.shared.ldap.entry.Value...)
+     * Adds some values to this attribute. If the new values are already present in
+     * the attribute values, the method has no effect.
+     * <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,
+     * a conversion is done. For instance, if we try to set some 
+     * StringValue into a Binary attribute, we just store the UTF-8 
+     * byte array encoding for this StringValue.
+     * </p>
+     * <p>
+     * If we try to store some BinaryValue in a HR attribute, we try to 
+     * convert those BinaryValue assuming they represent an UTF-8 encoded
+     * String. Of course, if it's not the case, the stored value will
+     * be incorrect.
+     * </p>
+     * <p>
+     * It's the responsibility of the caller to check if the stored
+     * values are consistent with the attribute's type.
+     * </p>
+     * <p>
+     * The caller can set the HR flag in order to enforce a type for 
+     * the current attribute, otherwise this type will be set while
+     * adding the first value, using the value's type to set the flag.
+     * </p>
+     * <p>
+     * <b>Note : </b>If the entry contains no value, and the unique added value
+     * is a null length value, then this value will be considered as
+     * a binary value.
+     * </p>
+     * @param val 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( ClientValue<?>... vals ) throws InvalidAttributeValueException, NamingException
+    public int add( Value<?>... vals )
     {
         int nbAdded = 0;
+        ClientBinaryValue nullBinaryValue = null;
+        ClientStringValue nullStringValue = null;
+        boolean nullValueAdded = false;
         
-        for ( ClientValue<?> val:vals )
+        for ( Value<?> val:vals )
         {
-            if ( add( val ) )
+            if ( val == null )
             {
-                nbAdded ++;
+                // We have a null value. If the HR flag is not set, we will consider 
+                // that the attribute is not HR. We may change this later
+                if ( isHR == null )
+                {
+                    // This is the first value. Add both types, as we 
+                    // don't know yet the attribute type's, but we may
+                    // know later if we add some new value.
+                    // We have to do that because we are using a Set,
+                    // and we can't remove the first element of the Set.
+                    nullBinaryValue = new ClientBinaryValue( null );
+                    nullStringValue = new ClientStringValue( null );
+                    
+                    values.add( nullBinaryValue );
+                    values.add( nullStringValue );
+                    nullValueAdded = true;
+                }
+                else if ( !isHR )
+                {
+                    // The attribute type is binary.
+                    nullBinaryValue = new ClientBinaryValue( null );
+                    
+                    // Don't add a value if it already exists. 
+                    if ( !values.contains( nullBinaryValue ) )
+                    {
+                        values.add( nullBinaryValue );
+                    }
+                    
+                }
+                else
+                {
+                    // The attribute is HR
+                    nullStringValue = new ClientStringValue( null );
+                    
+                    // Don't add a value if it already exists. 
+                    if ( !values.contains( nullStringValue ) )
+                    {
+                        values.add( nullStringValue );
+                    }
+                }
             }
+            else
+            {
+                // Let's check the value type. 
+                if ( val instanceof ClientStringValue )
+                {
+                    // We have a String value
+                    if ( isHR == null )
+                    {
+                        // The attribute type will be set to HR
+                        isHR = true;
+                        values.add( val );
+                    }
+                    else if ( !isHR )
+                    {
+                        // The attributeType is binary, convert the
+                        // value to a BinaryValue
+                        ClientBinaryValue cbv = new ClientBinaryValue();
+                        cbv.set( StringTools.getBytesUtf8( (String)val.get() ) );
+                        
+                        values.add( cbv );
+                    }
+                    else
+                    {
+                        // The attributeType is HR, simply add the value
+                        values.add( val );
+                    }
+                }
+                else
+                {
+                    // We have a Binary value
+                    if ( isHR == null )
+                    {
+                        // The attribute type will be set to binary
+                        isHR = false;
+                        values.add( val );
+                    }
+                    else if ( !isHR )
+                    {
+                        // The attributeType is not HR, simply add the value
+                        values.add( val );
+                    }
+                    else
+                    {
+                        // The attribute Type is HR, convert the
+                        // value to a StringValue
+                        ClientStringValue csv = new ClientStringValue();
+                        csv.set( StringTools.utf8ToString( (byte[])val.get() ) );
+                        
+                        values.add( csv );
+                    }
+                }
+            }
+
+            nbAdded++;
         }
-        
-        return nbAdded;
-    }
 
+        // Last, not least, if a nullValue has been added, and if other 
+        // values are all String, we have to keep the correct nullValue,
+        // and to remove the other
+        if ( nullValueAdded )
+        {
+            if ( isHR ) 
+            {
+                // Remove the Binary value
+                values.remove( nullBinaryValue );
+            }
+            else
+            {
+                // Remove the String value
+                values.remove( nullStringValue );
+            }
+        }
 
-    /**
-     * @see EntryAttribute#add(String)
-     */
-    public boolean add( String val ) throws InvalidAttributeValueException, NamingException
-    {
-        return add( new ClientStringValue( val ) );
+        return nbAdded;
     }
 
 
     /**
      * @see EntryAttribute#add(String...)
      */
-    public int add( String... vals ) throws NamingException
+    public int add( String... vals )
     {
         int nbAdded = 0;
         
-        for ( String val:vals )
+        // First, if the isHR flag is not set, we assume that the
+        // attribute is HR, because we are asked to add some strings.
+        if ( isHR == null )
         {
-            if ( add( val ) )
+            isHR = true;
+        }
+
+        // Check the attribute type.
+        if ( isHR )
+        {
+            for ( String val:vals )
+            {
+                if ( add( new ClientStringValue( val ) ) == 1 )
+                {
+                    nbAdded++;
+                }
+            }
+        }
+        else
+        {
+            // The attribute is binary. Transform the String to byte[]
+            for ( String val:vals )
             {
-                nbAdded ++;
+                byte[] valBytes = null;
+                
+                if ( val != null )
+                {
+                    valBytes = StringTools.getBytesUtf8( val );
+                }
+                
+                // Now call the add(Value) method
+                if ( add( new ClientBinaryValue( valBytes ) ) == 1 )
+                {
+                    nbAdded++;
+                }
             }
         }
         
@@ -279,26 +567,72 @@
     
     
     /**
-     * @see EntryAttribute#add(byte[])
-     */
-    public boolean add( byte[] val ) throws InvalidAttributeValueException, NamingException
-    {
-        return add( new ClientBinaryValue( val ) );
-    }
-
-    
-    /**
-     * @see EntryAttribute#add(byte[]...)
+     * Adds some values to this attribute. If the new values are already present in
+     * the attribute values, the method has no effect.
+     * <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,
+     * a conversion is done. For instance, if we try to set some String
+     * into a Binary attribute, we just store the UTF-8 byte array 
+     * encoding for this String.
+     * If we try to store some byte[] in a HR attribute, we try to 
+     * convert those byte[] assuming they represent an UTF-8 encoded
+     * String. Of course, if it's not the case, the stored value will
+     * be incorrect.
+     * <br>
+     * It's the responsibility of the caller to check if the stored
+     * values are consistent with the attribute's type.
+     * <br>
+     * The caller can set the HR flag in order to enforce a type for 
+     * the current attribute, otherwise this type will be set while
+     * adding the first value, using the value's type to set the flag.
+     *
+     * @param val 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 ) throws InvalidAttributeValueException, NamingException
+    public int add( byte[]... vals )
     {
         int nbAdded = 0;
         
-        for ( byte[] val:vals )
+        // First, if the isHR flag is not set, we assume that the
+        // attribute is not HR, because we are asked to add some byte[].
+        if ( isHR == null )
         {
-            if ( add( val ) )
+            isHR = false;
+        }
+
+        // Check the attribute type.
+        if ( isHR )
+        {
+            // The attribute is HR. Transform the byte[] to String
+            for ( byte[] val:vals )
             {
-                nbAdded ++;
+                String valString = null;
+                
+                if ( val != null )
+                {
+                    valString = StringTools.utf8ToString( val );
+                }
+                
+                // Now call the add(Value) method
+                if ( add( new ClientStringValue( valString ) ) == 1 )
+                {
+                    nbAdded++;
+                }
+            }
+        }
+        else
+        {
+            for ( byte[] val:vals )
+            {
+                if ( add( new ClientBinaryValue( val ) ) == 1 )
+                {
+                    nbAdded++;
+                }
             }
         }
         
@@ -307,8 +641,7 @@
     
     
     /**
-     * Remove all the values from this attribute type, including a 
-     * null value. 
+     * Remove all the values from this attribute.
      */
     public void clear()
     {
@@ -317,26 +650,75 @@
 
 
     /**
-     * @see EntryAttribute#contains(org.apache.directory.shared.ldap.entry.Value)
+     * <p>
+     * Indicates whether the specified values are some of the attribute's values.
+     * </p>
+     * <p>
+     * If the Attribute is HR, the binary values will be converted to String before
+     * being checked.
+     * </p>
+     *
+     * @param vals the values
+     * @return true if this attribute contains all the values, otherwise false
      */
-    public boolean contains( ClientValue<?> val )
+    public boolean contains( Value<?>... vals )
     {
-        return values.contains( val );
-    }
-
+        if ( isHR == null )
+        {
+            // If this flag is null, then there is no values.
+            return false;
+        }
 
-    /**
-     * @see EntryAttribute#contains(org.apache.directory.shared.ldap.entry.Value...)
-     */
-    public boolean contains( ClientValue<?>... vals )
-    {
-        // Iterate through all the values, and quit if we 
-        // don't find one in the values
-        for ( ClientValue<?> val:vals )
+        if ( isHR )
         {
-            if ( !values.contains( val ) )
+            // Iterate through all the values, convert the Binary values
+            // to String values, and quit id any of the values is not
+            // contained in the object
+            for ( Value<?> val:vals )
             {
-                return false;
+                if ( val instanceof ClientStringValue )
+                {
+                    if ( !values.contains( val ) )
+                    {
+                        return false;
+                    }
+                }
+                else
+                {
+                    byte[] binaryVal = (byte[])val.get();
+                    
+                    // We have to convert the binary value to a String
+                    if ( ! values.contains( new ClientStringValue( StringTools.utf8ToString( binaryVal ) ) ) )
+                    {
+                        return false;
+                    }
+                }
+            }
+        }
+        else
+        {
+            // Iterate through all the values, convert the String values
+            // to binary values, and quit id any of the values is not
+            // contained in the object
+            for ( Value<?> val:vals )
+            {
+                if ( val instanceof ClientBinaryValue )
+                {
+                    if ( !values.contains( val ) )
+                    {
+                        return false;
+                    }
+                }
+                else
+                {
+                    String stringVal = (String)val.get();
+                    
+                    // We have to convert the binary value to a String
+                    if ( ! values.contains( new ClientBinaryValue( StringTools.getBytesUtf8( stringVal ) ) ) )
+                    {
+                        return false;
+                    }
+                }
             }
         }
         
@@ -345,28 +727,50 @@
 
 
     /**
-     * @see EntryAttribute#contains(String)
-     */
-    public boolean contains( String val )
-    {
-        ClientStringValue value = new ClientStringValue( val );
-        
-        return values.contains( value );
-    }
-
-
-    /**
-     * @see EntryAttribute#contains(String...)
+     * <p>
+     * Indicates whether the specified values are some of the attribute's values.
+     * </p>
+     * <p>
+     * If the Attribute is not HR, the values will be converted to byte[]
+     * </p>
+     *
+     * @param vals the values
+     * @return true if this attribute contains all the values, otherwise false
      */
     public boolean contains( String... vals )
     {
-        // Iterate through all the values, and quit if we 
-        // don't find one in the values
-        for ( String val:vals )
+        if ( isHR == null )
+        {
+            // If this flag is null, then there is no values.
+            return false;
+        }
+
+        if ( isHR )
         {
-            if ( !contains( val ) )
+            // Iterate through all the values, and quit if we 
+            // don't find one in the values
+            for ( String val:vals )
             {
-                return false;
+                if ( !contains( new ClientStringValue( val ) ) )
+                {
+                    return false;
+                }
+            }
+        }
+        else
+        {
+            // As the attribute type is binary, we have to convert 
+            // the values before checking for them in the values
+            // Iterate through all the values, and quit if we 
+            // don't find one in the values
+            for ( String val:vals )
+            {
+                byte[] binaryVal = StringTools.getBytesUtf8( val );
+
+                if ( !contains( new ClientBinaryValue( binaryVal ) ) )
+                {
+                    return false;
+                }
             }
         }
         
@@ -375,45 +779,131 @@
     
     
     /**
-     * @see EntryAttribute#contains(byte[])
+     * <p>
+     * Indicates whether the specified values are some of the attribute's values.
+     * </p>
+     * <p>
+     * If the Attribute is HR, the values will be converted to String
+     * </p>
+     *
+     * @param vals the values
+     * @return true if this attribute contains all the values, otherwise false
      */
-    public boolean contains( byte[] val )
+    public boolean contains( byte[]... vals )
     {
-        ClientBinaryValue sbv = new ClientBinaryValue( val );
-        return values.contains( sbv );
-    }
+        if ( isHR == null )
+        {
+            // If this flag is null, then there is no values.
+            return false;
+        }
 
+        if ( !isHR )
+        {
+            // Iterate through all the values, and quit if we 
+            // don't find one in the values
+            for ( byte[] val:vals )
+            {
+                if ( !contains( new ClientBinaryValue( val ) ) )
+                {
+                    return false;
+                }
+            }
+        }
+        else
+        {
+            // As the attribute type is String, we have to convert 
+            // the values before checking for them in the values
+            // Iterate through all the values, and quit if we 
+            // don't find one in the values
+            for ( byte[] val:vals )
+            {
+                String stringVal = StringTools.utf8ToString( val );
 
+                if ( !contains( new ClientStringValue( stringVal ) ) )
+                {
+                    return false;
+                }
+            }
+        }
+        
+        return true;
+    }
+    
+    
     /**
-     * @see EntryAttribute#contains(byte[]...)
+     * @see EntryAttribute#contains(Object...)
      */
-    public boolean contains( byte[]... vals )
+    public boolean contains( Object... vals )
     {
+        boolean isHR = true;
+        boolean seen = false;
+        
         // Iterate through all the values, and quit if we 
         // don't find one in the values
-        for ( byte[] val:vals )
+        for ( Object val:vals )
         {
-            if ( !contains( val ) )
+            if ( ( val instanceof String ) ) 
             {
-                return false;
+                if ( !seen )
+                {
+                    isHR = true;
+                    seen = true;
+                }
+
+                if ( isHR )
+                {
+                    if ( !contains( (String)val ) )
+                    {
+                        return false;
+                    }
+                }
+                else
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                if ( !seen )
+                {
+                    isHR = false;
+                    seen = true;
+                }
+
+                if ( !isHR )
+                {
+                    if ( !contains( (byte[])val ) )
+                    {
+                        return false;
+                    }
+                }
+                else
+                {
+                    return false;
+                }
             }
         }
         
         return true;
     }
-    
+
     
     /**
+     * <p>
      * Get the first value of this attribute. If there is none, 
      * null is returned.
-     * 
-     * Note : as we are storing values into a Set, one can't assume
-     * the values to be ordered in any way. This method is meant to
-     * be used if the attribute hold only one value.
+     * </p>
+     * <p>
+     * Note : even if we are storing values into a Set, one can assume
+     * the values are ordered following the insertion order.
+     * </p>
+     * <p> 
+     * This method is meant to be used if the attribute hold only one value.
+     * </p>
      * 
      *  @return The first value for this attribute.
      */
-    public ClientValue<?> get()
+    public Value<?> get()
     {
         if ( values.isEmpty() )
         {
@@ -425,21 +915,28 @@
 
 
     /**
-     * Get all the stored values.
-     * 
-     * @return An iterator over the values stored into the attribute
+     * Returns an iterator over all the attribute's values.
+     * <p>
+     * The effect on the returned enumeration of adding or removing values of
+     * the attribute is not specified.
+     * </p>
+     * <p>
+     * This method will throw any <code>NamingException</code> that occurs.
+     * </p>
+     *
+     * @return an enumeration of all values of the attribute
      */
-    public Iterator<ClientValue<?>> getAll()
+    public Iterator<Value<?>> getAll()
     {
         return iterator();
     }
 
 
     /**
-     * Get the number or values stored in the attribute
-     * 
-     * @return the number of stored values. As 'null' can be a valid
-     * value, it is counted as one result, not 0.
+     * Retrieves the number of values in this attribute.
+     *
+     * @return the number of values in this attribute, including any values
+     * wrapping a null value if there is one
      */
     public int size()
     {
@@ -448,26 +945,60 @@
 
 
     /**
-     * @see EntryAttribute#remove(org.apache.directory.shared.ldap.entry.Value)
-     */
-    public boolean remove( ClientValue<?> val )
-    {
-        return values.remove( val );
-    }
-
-
-    /**
-     * @see EntryAttribute#remove(org.apache.directory.shared.ldap.entry.Value...)
+     * <p>
+     * Removes all the  values that are equal to the given values.
+     * </p>
+     * <p>
+     * Returns true if all the values are removed.
+     * </p>
+     * <p>
+     * If the attribute type is HR and some value which are not String, we
+     * will convert the values first (same thing for a non-HR attribute).
+     * </p>
+     *
+     * @param vals the values to be removed
+     * @return true if all the values are removed, otherwise false
      */
-    public boolean remove( ClientValue<?>... vals )
+    public boolean remove( Value<?>... vals )
     {
-        boolean removed = false;
+        if ( ( isHR == null ) || ( values.size() == 0 ) ) 
+        {
+            // Trying to remove a value from an empty list will fail
+            return false;
+        }
         
-        // Loop through all the values to remove. If one of
-        // them is not present, the method will return false.
-        for ( ClientValue<?> val:vals )
+        boolean removed = true;
+        
+        if ( isHR )
+        {
+            for ( Value<?> val:vals )
+            {
+                if ( val instanceof ClientStringValue )
+                {
+                    removed &= values.remove( val );
+                }
+                else
+                {
+                    // Convert the binary value to a string value
+                    byte[] binaryVal = (byte[])val.get();
+                    removed &= values.remove( new ClientStringValue( StringTools.utf8ToString( binaryVal ) ) );
+                }
+            }
+        }
+        else
         {
-            removed &= values.remove( val );
+            for ( Value<?> val:vals )
+            {
+                if ( val instanceof ClientBinaryValue )
+                {
+                    removed &= values.remove( val );
+                }
+                else
+                {
+                    String stringVal = (String)val.get();
+                    removed &= values.remove( new ClientBinaryValue( StringTools.getBytesUtf8( stringVal ) ) );
+                }
+            }
         }
         
         return removed;
@@ -475,26 +1006,95 @@
 
 
     /**
-     * @see EntryAttribute#remove(byte[])
+     * <p>
+     * Removes all the  values that are equal to the given values.
+     * </p>
+     * <p>
+     * Returns true if all the values are removed.
+     * </p>
+     * <p>
+     * If the attribute type is HR, then the values will be first converted
+     * to String
+     * </p>
+     *
+     * @param vals the values to be removed
+     * @return true if all the values are removed, otherwise false
      */
-    public boolean remove( byte[] val )
+    public boolean remove( byte[]... vals )
     {
-        ClientBinaryValue sbv = new ClientBinaryValue( val );
-        return values.remove( sbv );
+        if ( ( isHR == null ) || ( values.size() == 0 ) ) 
+        {
+            // Trying to remove a value from an empty list will fail
+            return false;
+        }
+        
+        boolean removed = true;
+        
+        if ( !isHR )
+        {
+            // The attribute type is not HR, we can directly process the values
+            for ( byte[] val:vals )
+            {
+                ClientBinaryValue value = new ClientBinaryValue( val );
+                removed &= values.remove( value );
+            }
+        }
+        else
+        {
+            // The attribute type is String, we have to convert the values
+            // to String before removing them
+            for ( byte[] val:vals )
+            {
+                ClientStringValue value = new ClientStringValue( StringTools.utf8ToString( val ) );
+                removed &= values.remove( value );
+            }
+        }
+        
+        return removed;
     }
 
 
     /**
-     * @see EntryAttribute#remove(byte[]...)
+     * Removes all the  values that are equal to the given values.
+     * <p>
+     * Returns true if all the values are removed.
+     * </p>
+     * <p>
+     * If the attribute type is not HR, then the values will be first converted
+     * to byte[]
+     * </p>
+     *
+     * @param vals the values to be removed
+     * @return true if all the values are removed, otherwise false
      */
-    public boolean remove( byte[]... vals )
+    public boolean remove( String... vals )
     {
+        if ( ( isHR == null ) || ( values.size() == 0 ) ) 
+        {
+            // Trying to remove a value from an empty list will fail
+            return false;
+        }
+        
         boolean removed = true;
         
-        for ( byte[] val:vals )
+        if ( isHR )
         {
-            ClientBinaryValue value = new ClientBinaryValue( val );
-            removed &= values.remove( value );
+            // The attribute type is HR, we can directly process the values
+            for ( String val:vals )
+            {
+                ClientStringValue value = new ClientStringValue( val );
+                removed &= values.remove( value );
+            }
+        }
+        else
+        {
+            // The attribute type is binary, we have to convert the values
+            // to byte[] before removing them
+            for ( String val:vals )
+            {
+                ClientBinaryValue value = new ClientBinaryValue( StringTools.getBytesUtf8( val ) );
+                removed &= values.remove( value );
+            }
         }
         
         return removed;
@@ -502,42 +1102,214 @@
 
 
     /**
-     * @see EntryAttribute#remove(String)
+     * An iterator on top of the stored values.
+     * 
+     * @return an iterator over the stored values.
      */
-    public boolean remove( String val )
+    public Iterator<Value<?>> iterator()
     {
-        ClientStringValue ssv = new ClientStringValue( val );
-        return values.remove( ssv );
+        return values.iterator();
+    }
+    
+    
+    /**
+     * Puts some values to this attribute.
+     * <p>
+     * The new values will replace the previous values.
+     * </p>
+     * <p>
+     * This method returns the number of values that were put.
+     * </p>
+     *
+     * @param val some values to be put which may be null
+     * @return the number of added values, or 0 if none has been added
+     */
+    public int put( String... vals )
+    {
+        values.clear();
+        return add( vals );
+    }
+    
+    
+    /**
+     * Puts some values to this attribute.
+     * <p>
+     * The new values will replace the previous values.
+     * </p>
+     * <p>
+     * This method returns the number of values that were put.
+     * </p>
+     *
+     * @param val some values to be put which may be null
+     * @return the number of added values, or 0 if none has been added
+     */
+    public int put( byte[]... vals )
+    {
+        values.clear();
+        return add( vals );
     }
 
-
+    
     /**
-     * @see EntryAttribute#remove(String...)
+     * Puts some values to this attribute.
+     * <p>
+     * The new values are replace the previous values.
+     * </p>
+     * <p>
+     * This method returns the number of values that were put.
+     * </p>
+     *
+     * @param val some values to be put which may be null
+     * @return the number of added values, or 0 if none has been added
      */
-    public boolean remove( String... vals )
+    public int put( Value<?>... vals )
     {
-        boolean removed = true;
+        values.clear();
+        return add( vals );
+    }
+    
+    
+    /**
+     * <p>
+     * Puts a list of values into this attribute.
+     * </p>
+     * <p>
+     * The new values will replace the previous values.
+     * </p>
+     * <p>
+     * This method returns the number of values that were put.
+     * </p>
+     *
+     * @param vals the values to be put
+     * @return the number of added values, or 0 if none has been added
+     */
+    public int put( List<Value<?>> vals )
+    {
+        values.clear();
+        
+        // Transform the List to an array
+        Value<?>[] valArray = new Value<?>[vals.size()];
+        return add( vals.toArray( valArray ) );
+    }
+    
+    //-------------------------------------------------------------------------
+    // Overloaded Object classes
+    //-------------------------------------------------------------------------
+    /**
+     * The hashCode is based on the id, the isHR flag and 
+     * on the internal values.
+     *  
+     * @see Object#hashCode()
+     */
+    public int hashCode()
+    {
+        int h = 37;
         
-        for ( String val:vals )
+        if ( isHR != null )
         {
-            ClientStringValue value = new ClientStringValue( val );
-            removed &= values.remove( value );
+            h = h*17 + isHR.hashCode();
         }
         
-        return removed;
+        if ( id != null )
+        {
+            h = h*17 + id.hashCode();
+        }
+        
+        for ( Value<?> value:values )
+        {
+            h = h*17 + value.hashCode();
+        }
+        
+        return h;
     }
-
-
+    
+    
     /**
-     * An iterator on top of the stored values.
-     * 
-     * @return an iterator over the stored values.
+     * @see Object#equals(Object)
      */
-    public Iterator<ClientValue<?>> iterator()
+    public boolean equals( Object obj )
     {
-        return values.iterator();
+        if ( obj == this )
+        {
+            return true;
+        }
+        
+        if ( ! (obj instanceof EntryAttribute ) )
+        {
+            return false;
+        }
+        
+        EntryAttribute other = (EntryAttribute)obj;
+        
+        if ( id == null )
+        {
+            if ( other.getId() != null )
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if ( other.getId() == null )
+            {
+                return false;
+            }
+            else
+            {
+                if ( !id.equals( other.getId() ) )
+                {
+                    return false;
+                }
+            }
+        }
+        
+        if ( isHR() !=  other.isHR() )
+        {
+            return false;
+        }
+        
+        if ( values.size() != other.size() )
+        {
+            return false;
+        }
+        
+        for ( Value<?> val:values )
+        {
+            if ( ! other.contains( val ) )
+            {
+                return false;
+            }
+        }
+        
+        return true;
     }
     
+    
+    /**
+     * @see Cloneable#clone()
+     */
+    public EntryAttribute clone()
+    {
+        try
+        {
+            DefaultClientAttribute attribute = (DefaultClientAttribute)super.clone();
+            
+            attribute.values = new LinkedHashSet<Value<?>>( values.size() );
+            
+            for ( Value<?> value:values )
+            {
+                attribute.values.add( value.clone() );
+            }
+            
+            return attribute;
+        }
+        catch ( CloneNotSupportedException cnse )
+        {
+            return null;
+        }
+    }
+    
+    
     /**
      * @see Object#toString() 
      */
@@ -547,7 +1319,7 @@
         
         if ( ( values != null ) && ( values.size() != 0 ) )
         {
-            for ( ClientValue<?> value:values )
+            for ( Value<?> value:values )
             {
                 sb.append( "    " ).append( upId ).append( ": " ).append( value ).append( '\n' );
             }
@@ -559,5 +1331,4 @@
         
         return sb.toString();
     }
-
 }

Modified: directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/ldif/LdifReader.java
URL: http://svn.apache.org/viewvc/directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/ldif/LdifReader.java?rev=638218&r1=638217&r2=638218&view=diff
==============================================================================
--- directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/ldif/LdifReader.java (original)
+++ directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/ldif/LdifReader.java Mon Mar 17 22:07:20 2008
@@ -152,7 +152,7 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class LdifReader implements Iterator<Entry>
+public class LdifReader implements Iterator<LdifEntry>
 {
     /** A logger */
     private static final Logger LOG = LoggerFactory.getLogger( LdifReader.class );
@@ -211,7 +211,7 @@
     protected static final int ATTRVAL_SPEC_OR_SEP = 2;
 
     /** Iterator prefetched entry */
-    protected Entry prefetched;
+    protected LdifEntry prefetched;
 
     /** The ldif Reader */
     protected Reader in;
@@ -855,7 +855,7 @@
      * @throws NamingException
      *             If anything goes wrong
      */
-    public void parseAttributeValue( Entry entry, String line, String lowerLine ) throws NamingException
+    public void parseAttributeValue( LdifEntry entry, String line, String lowerLine ) throws NamingException
     {
         int colonIndex = line.indexOf( ':' );
 
@@ -884,7 +884,7 @@
      * @throws NamingException
      *             If anything goes wrong
      */
-    private void parseModRdn( Entry entry, Iterator<String> iter ) throws NamingException
+    private void parseModRdn( LdifEntry entry, Iterator<String> iter ) throws NamingException
     {
         // We must have two lines : one starting with "newrdn:" or "newrdn::",
         // and the second starting with "deleteoldrdn:"
@@ -955,7 +955,7 @@
      * @param iter
      *            The lines
      */
-    private void parseModify( Entry entry, Iterator<String> iter ) throws NamingException
+    private void parseModify( LdifEntry entry, Iterator<String> iter ) throws NamingException
     {
         int state = MOD_SPEC;
         String modified = null;
@@ -1105,7 +1105,7 @@
      *            The associated control, if any
      * @return A modification entry
      */
-    private void parseChange( Entry entry, Iterator<String> iter, ChangeType operation, Control control ) throws NamingException
+    private void parseChange( LdifEntry entry, Iterator<String> iter, ChangeType operation, Control control ) throws NamingException
     {
         // The changetype and operation has already been parsed.
         entry.setChangeType( operation );
@@ -1187,7 +1187,7 @@
      * &lt;distinguishedName&gt; | "dn::" &lt;fill&gt; &lt;base64-distinguishedName&gt;
      * &lt;changerecord&gt; ::= "changetype:" &lt;fill&gt; &lt;change-op&gt;
      */
-    private Entry parseEntry() throws NamingException
+    private LdifEntry parseEntry() throws NamingException
     {
         if ( ( lines == null ) || ( lines.size() == 0 ) )
         {
@@ -1201,7 +1201,7 @@
         String dn = parseDn( line );
 
         // Ok, we have found a DN
-        Entry entry = new Entry();
+        LdifEntry entry = new LdifEntry();
         entry.setDn( dn );
 
         // We remove this dn from the lines
@@ -1501,7 +1501,7 @@
      * @throws NamingException
      *             If the parsing fails
      */
-    public List<Entry> parseLdifFile( String fileName ) throws NamingException
+    public List<LdifEntry> parseLdifFile( String fileName ) throws NamingException
     {
         return parseLdifFile( fileName, Charset.forName( StringTools.getDefaultCharsetName() ).toString() );
     }
@@ -1517,7 +1517,7 @@
      * @throws NamingException
      *             If the parsing fails
      */
-    public List<Entry> parseLdifFile( String fileName, String encoding ) throws NamingException
+    public List<LdifEntry> parseLdifFile( String fileName, String encoding ) throws NamingException
     {
         if ( StringTools.isEmpty( fileName ) )
         {
@@ -1558,13 +1558,13 @@
      * @throws NamingException
      *             If something went wrong
      */
-    public List<Entry> parseLdif( String ldif ) throws NamingException
+    public List<LdifEntry> parseLdif( String ldif ) throws NamingException
     {
         LOG.debug( "Starts parsing ldif buffer" );
 
         if ( StringTools.isEmpty( ldif ) )
         {
-            return new ArrayList<Entry>();
+            return new ArrayList<LdifEntry>();
         }
 
         StringReader strIn = new StringReader( ldif );
@@ -1572,7 +1572,7 @@
 
         try
         {
-            List<Entry> entries = parseLdif( inf );
+            List<LdifEntry> entries = parseLdif( inf );
 
             if ( LOG.isDebugEnabled() )
             {
@@ -1597,13 +1597,13 @@
      * 
      * @return the next LDIF as a String.
      */
-    public Entry next() throws NoSuchElementException
+    public LdifEntry next() throws NoSuchElementException
     {
         try
         {
             LOG.debug( "next(): -- called" );
 
-            Entry entry = prefetched;
+            LdifEntry entry = prefetched;
             readLines();
 
             try
@@ -1652,7 +1652,7 @@
     /**
      * @return An iterator on the file
      */
-    public Iterator<Entry> iterator()
+    public Iterator<LdifEntry> iterator()
     {
         return this;
     }
@@ -1683,10 +1683,10 @@
      * @throws NamingException
      *             If something went wrong
      */
-    public List<Entry> parseLdif( BufferedReader inf ) throws NamingException
+    public List<LdifEntry> parseLdif( BufferedReader inf ) throws NamingException
     {
         // Create a list that will contain the read entries
-        List<Entry> entries = new ArrayList<Entry>();
+        List<LdifEntry> entries = new ArrayList<LdifEntry>();
 
         this.in = inf;
 
@@ -1697,7 +1697,7 @@
         // When done, get the entries one by one.
         while ( hasNext() )
         {
-            Entry entry = next();
+            LdifEntry entry = next();
 
             if ( error != null )
             {

Modified: directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/ldif/LdifUtils.java
URL: http://svn.apache.org/viewvc/directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/ldif/LdifUtils.java?rev=638218&r1=638217&r2=638218&view=diff
==============================================================================
--- directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/ldif/LdifUtils.java (original)
+++ directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/ldif/LdifUtils.java Mon Mar 17 22:07:20 2008
@@ -188,7 +188,7 @@
      * @return the corresponding LDIF as a String
      * @throws NamingException If a naming exception is encountered.
      */
-    public static String convertToLdif( Entry entry ) throws NamingException
+    public static String convertToLdif( LdifEntry entry ) throws NamingException
     {
         return convertToLdif( entry, DEFAULT_LINE_LENGTH );
     }
@@ -199,7 +199,7 @@
      * @return the corresponding LDIF as a String
      * @throws NamingException If a naming exception is encountered.
      */
-    public static String convertToLdif( Entry entry, int length ) throws NamingException
+    public static String convertToLdif( LdifEntry entry, int length ) throws NamingException
     {
         StringBuilder sb = new StringBuilder();
         
@@ -471,9 +471,9 @@
      * @return a reverse LDIF
      * @throws NamingException If something went wrong
      */
-    public static Entry reverseAdd( LdapDN dn ) throws NamingException
+    public static LdifEntry reverseAdd( LdapDN dn ) throws NamingException
     {
-        Entry entry = new Entry();
+        LdifEntry entry = new LdifEntry();
         entry.setChangeType( ChangeType.Delete );
         entry.setDn( dn.getUpName() );
         return entry;
@@ -489,9 +489,9 @@
      * @return A reverse LDIF
      * @throws NamingException If something went wrong
      */
-    public static Entry reverseDel( LdapDN dn, Attributes deletedEntry ) throws NamingException
+    public static LdifEntry reverseDel( LdapDN dn, Attributes deletedEntry ) throws NamingException
     {
-        Entry entry = new Entry();
+        LdifEntry entry = new LdifEntry();
         
         entry.setDn( dn.getUpName() );
         entry.setChangeType( ChangeType.Add );
@@ -516,9 +516,9 @@
      * @return a reverse LDIF
      * @throws NamingException if something went wrong
      */
-    public static Entry reverseModifyDn( LdapDN newSuperiorDn, LdapDN modifiedDn ) throws NamingException
+    public static LdifEntry reverseModifyDn( LdapDN newSuperiorDn, LdapDN modifiedDn ) throws NamingException
     {
-        Entry entry = new Entry();
+        LdifEntry entry = new LdifEntry();
         LdapDN currentParent;
         LdapDN newDn;
 
@@ -551,9 +551,9 @@
     }
 
 
-    public static Entry reverseRename( Attributes t0, LdapDN t0_dn, Rdn t1_rdn ) throws NamingException
+    public static LdifEntry reverseRename( Attributes t0, LdapDN t0_dn, Rdn t1_rdn ) throws NamingException
     {
-        Entry entry = new Entry();
+        LdifEntry entry = new LdifEntry();
         LdapDN parent;
         LdapDN newDn;
 
@@ -598,7 +598,7 @@
      * @return A reverse LDIF
      * @throws NamingException If something went wrong
      */
-    public static Entry reverseModifyRdn( Attributes t0, LdapDN t1_parentDn, LdapDN t0_dn, Rdn t1_rdn )
+    public static LdifEntry reverseModifyRdn( Attributes t0, LdapDN t1_parentDn, LdapDN t0_dn, Rdn t1_rdn )
             throws NamingException
     {
         if ( t0_dn == null )
@@ -630,7 +630,7 @@
         // -------------------------------------------------------------------
 
         // the reverse LDIF we will create
-        Entry reverse = new Entry();
+        LdifEntry reverse = new LdifEntry();
 
         // take the dn before the forward change was applied, and get it's
         // parent, this parent will be the newSuperiorDn to be used for the
@@ -709,13 +709,13 @@
      * @return A reversed LDIF
      * @throws NamingException If something went wrong
      */
-    public static Entry reverseModify( LdapDN dn, List<ModificationItemImpl> forwardModifications,
+    public static LdifEntry reverseModify( LdapDN dn, List<ModificationItemImpl> forwardModifications,
                                        Attributes modifiedEntry ) throws NamingException
     {
         // First, protect the original entry by cloning it : we will modify it
         Attributes clonedEntry = ( Attributes ) modifiedEntry.clone();
 
-        Entry entry = new Entry();
+        LdifEntry entry = new LdifEntry();
         entry.setChangeType( ChangeType.Modify );
 
         entry.setDn( dn.getUpName() );

Modified: directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/name/AttributeTypeAndValue.java
URL: http://svn.apache.org/viewvc/directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/name/AttributeTypeAndValue.java?rev=638218&r1=638217&r2=638218&view=diff
==============================================================================
--- directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/name/AttributeTypeAndValue.java (original)
+++ directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/name/AttributeTypeAndValue.java Mon Mar 17 22:07:20 2008
@@ -69,7 +69,7 @@
     private String upType;
 
     /** The name value. It can be a String or a byte array */
-    private Object value;
+    private Object normValue;
 
     /** The name user provided value. It can be a String or a byte array */
     private Object upValue;
@@ -97,7 +97,7 @@
     {
         normType = null;
         upType = null;
-        value = null;
+        normValue = null;
         upValue = null;
         upName = "";
         start = -1;
@@ -156,11 +156,11 @@
         {
             if ( normValue instanceof String )
             {
-                this.value = StringTools.isEmpty( ( String ) normValue ) ? "" : normValue;
+                this.normValue = StringTools.isEmpty( ( String ) normValue ) ? "" : normValue;
             }
             else
             {
-                this.value = normValue;
+                this.normValue = normValue;
             }
 
             if ( upValue instanceof String )
@@ -179,11 +179,11 @@
     
             if ( normValue instanceof String )
             {
-                this.value = StringTools.isEmpty( ( String ) normValue ) ? "" : normValue;
+                this.normValue = StringTools.isEmpty( ( String ) normValue ) ? "" : normValue;
             }
             else
             {
-                this.value = normValue;
+                this.normValue = normValue;
             }
         }
 
@@ -194,6 +194,38 @@
 
 
     /**
+     * Construct an AttributeTypeAndValue. The type and value are normalized :
+     * <li> the type is trimmed and lowercased </li>
+     * <li> the value is trimmed </li>
+     * <p>
+     * Note that the upValue should <b>not</b> be null or empty, or resolved
+     * to an empty string after having trimmed it. 
+     *
+     * @param upType The Usrr Provided type
+     * @param normType The normalized type
+     * @param upValue The User Provided value
+     * @param normValue The normalized value
+     */
+    /**No protection*/ AttributeTypeAndValue( 
+                            String upType, 
+                            String normType, 
+                            Object upValue, 
+                            Object normValue,
+                            int start, 
+                            int length, 
+                            String upName )
+    {
+        this.upType = upType;
+        this.normType = normType;
+        this.upValue = upValue;
+        this.normValue = normValue;
+        this.start = start;
+        this.length = length;
+        this.upName = upName;
+    }
+
+    
+    /**
      * Get the normalized type of a AttributeTypeAndValue
      *
      * @return The normalized type
@@ -283,9 +315,9 @@
      *
      * @return The value
      */
-    public Object getValue()
+    public Object getNormValue()
     {
-        return value;
+        return normValue;
     }
 
     /**
@@ -315,15 +347,15 @@
      * @param value
      *            The value of the AttributeTypeAndValue
      */
-    public void setValue( Object upValue, Object value )
+    public void setValue( Object upValue, Object normValue )
     {
-        if ( value instanceof String )
+        if ( normValue instanceof String )
         {
-            this.value = StringTools.isEmpty( ( String ) value ) ? "" : ( String ) value;
+            this.normValue = StringTools.isEmpty( ( String ) normValue ) ? "" : ( String ) normValue;
         }
         else
         {
-            this.value = value;
+            this.normValue = normValue;
         }
 
         this.upValue = upValue;
@@ -378,11 +410,11 @@
 
         if ( StringTools.isEmpty( newValue ) )
         {
-            this.value = "";
+            this.normValue = "";
         }
         else
         {
-            this.value = newValue;
+            this.normValue = newValue;
         }
 
         upName = upName.substring( 0, upName.indexOf( '=' ) + 1 ) + value;
@@ -410,8 +442,9 @@
 
 
     /**
-     * Compares two NameComponents. They are equals if : - types are equals,
-     * case insensitive, - values are equals, case sensitive
+     * Compares two NameComponents. They are equals if : 
+     * - types are equals, case insensitive, 
+     * - values are equals, case sensitive
      *
      * @param object
      * @return 0 if both NC are equals, otherwise a positive value if the
@@ -432,7 +465,7 @@
             }
             else
             {
-                return compareValue( value, nc.value, CASE_SENSITIVE );
+                return compareValue( normValue, nc.normValue, CASE_SENSITIVE );
             }
         }
         else
@@ -443,8 +476,9 @@
 
 
     /**
-     * Compares two NameComponents. They are equals if : - types are equals,
-     * case insensitive, - values are equals, case insensitive
+     * Compares two NameComponents. They are equals if : 
+     * - types are equals, case insensitive, 
+     * - values are equals, case insensitive
      *
      * @param object
      * @return 0 if both NC are equals, otherwise a positive value if the
@@ -465,7 +499,7 @@
             }
             else
             {
-                return compareValue( value, nc.value, CASE_INSENSITIVE );
+                return compareValue( normValue, nc.normValue, CASE_INSENSITIVE );
             }
         }
         else
@@ -572,7 +606,7 @@
      */
     public String normalize()
     {
-        if ( value instanceof String )
+        if ( normValue instanceof String )
         {
         	// The result will be gathered in a stringBuilder
             StringBuilder sb = new StringBuilder();
@@ -580,7 +614,7 @@
             // First, store the type and the '=' char
             sb.append( normType ).append( '=' );
             
-            String normalizedValue =  ( String ) value;
+            String normalizedValue =  ( String ) normValue;
             int valueLength = normalizedValue.length();
             boolean escaped = false;
             
@@ -680,7 +714,7 @@
         else
         {
             return normType + "=#"
-                + StringTools.dumpHexPairs( ( byte[] ) value );
+                + StringTools.dumpHexPairs( ( byte[] ) normValue );
         }
     }
 
@@ -695,7 +729,7 @@
         int result = 37;
 
         result = result*17 + ( normType != null ? normType.hashCode() : 0 );
-        result = result*17 + ( value != null ? value.hashCode() : 0 );
+        result = result*17 + ( normValue != null ? normValue.hashCode() : 0 );
 
         return result;
     }
@@ -734,26 +768,26 @@
         }
             
         // Compare the values
-        if ( value == null )
+        if ( normValue == null )
         {
-            return instance.value == null;
+            return instance.normValue == null;
         }
-        else if ( value instanceof String )
+        else if ( normValue instanceof String )
         {
-            if ( instance.value instanceof String )
+            if ( instance.normValue instanceof String )
             {
-                return value.equals( instance.value );
+                return normValue.equals( instance.normValue );
             }
             else
             {
                 return false;
             }
         }
-        else if ( value instanceof byte[] )
+        else if ( normValue instanceof byte[] )
         {
-            if ( instance.value instanceof byte[] )
+            if ( instance.normValue instanceof byte[] )
             {
-                return Arrays.equals( (byte[])value, (byte[])instance.value );
+                return Arrays.equals( (byte[])normValue, (byte[])instance.normValue );
             }
             else
             {
@@ -798,7 +832,7 @@
              ( start < 0 ) ||
              ( length < 2 ) ||             // At least a type and '='
              ( upValue == null ) ||
-             ( value == null ) )
+             ( normValue == null ) )
         {
             String message = "Cannot serialize an wrong ATAV, ";
             
@@ -826,7 +860,7 @@
             {
                 message += "the upValue should not be null";
             }
-            else if ( value == null )
+            else if ( normValue == null )
             {
                 message += "the value should not be null";
             }
@@ -841,21 +875,21 @@
         out.writeUTF( upType );
         out.writeUTF( normType );
         
-        boolean isHR = ( value instanceof String );
+        boolean isHR = ( normValue instanceof String );
         
         out.writeBoolean( isHR );
         
         if ( isHR )
         {
             out.writeUTF( (String)upValue );
-            out.writeUTF( (String)value );
+            out.writeUTF( (String)normValue );
         }
         else
         {
             out.writeInt( ((byte[])upValue).length );
             out.write( (byte[])upValue );
-            out.writeInt( ((byte[])value).length );
-            out.write( (byte[])value );
+            out.writeInt( ((byte[])normValue).length );
+            out.write( (byte[])normValue );
         }
         
         out.flush();
@@ -882,7 +916,7 @@
         if ( isHR )
         {
             upValue = in.readUTF();
-            value = in.readUTF();
+            normValue = in.readUTF();
         }
         else
         {
@@ -891,8 +925,8 @@
             in.readFully( (byte[])upValue );
 
             int valueLength = in.readInt();
-            value = new byte[valueLength];
-            in.readFully( (byte[])value );
+            normValue = new byte[valueLength];
+            in.readFully( (byte[])normValue );
         }
     }
     
@@ -913,9 +947,9 @@
 
         sb.append( normType ).append( "=" );
 
-        if ( value != null )
+        if ( normValue != null )
         {
-            sb.append( value );
+            sb.append( normValue );
         }
 
         return sb.toString();

Modified: directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/name/LdapDN.java
URL: http://svn.apache.org/viewvc/directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/name/LdapDN.java?rev=638218&r1=638217&r2=638218&view=diff
==============================================================================
--- directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/name/LdapDN.java (original)
+++ directory/sandbox/akarasulu/bigbang/shared/ldap/src/main/java/org/apache/directory/shared/ldap/name/LdapDN.java Mon Mar 17 22:07:20 2008
@@ -214,6 +214,18 @@
 
 
     /**
+     * Create a DN when deserializing it.
+     */
+    /* No protection */ LdapDN( String upName, String normName, byte[] bytes )
+    {
+        normalized = true;
+        this.upName = upName;
+        this.normName = normName;
+        this.bytes = bytes;
+    }
+
+
+    /**
      * Static factory which creates a normalized DN from a String and a Map of OIDs.
      *
      * @param name The DN as a String
@@ -295,7 +307,7 @@
      */
     public String toNormName()
     {
-        if ( ( rdns == null ) || ( rdns.size() == 0 ) )
+        if ( rdns.size() == 0 )
         {
             bytes = null;
             return "";
@@ -351,7 +363,7 @@
      */
     private String toUpName()
     {
-        if ( ( rdns == null ) || ( rdns.size() == 0 ) )
+        if ( rdns.size() == 0 )
         {
             upName = "";
         }
@@ -491,12 +503,9 @@
     {
         int result = 37;
 
-        if ( ( rdns != null ) && ( rdns.size() != 0 ) )
+        for ( Rdn rdn : rdns )
         {
-            for ( Rdn rdn : rdns )
-            {
-                result = result * 17 + rdn.hashCode();
-            }
+            result = result * 17 + rdn.hashCode();
         }
 
         return result;
@@ -526,9 +535,9 @@
 
 
     /**
-     * Get the number of NameComponent conatained in this LdapDN
+     * Get the number of NameComponent contained in this LdapDN
      *
-     * @return The number of NameComponent conatained in this LdapDN
+     * @return The number of NameComponent contained in this LdapDN
      */
     public int size()
     {
@@ -639,7 +648,6 @@
                 }
                 catch ( InvalidNameException e )
                 {
-                    e.printStackTrace();
                     LOG.error( "Failed to parse RDN for name " + name.toString(), e );
                     return false;
                 }
@@ -1173,6 +1181,25 @@
         return this;
     }
 
+
+    /**
+     * Adds a single RDN to a specific position.
+     *
+     * @param newRdn the RDN to add
+     * @param pos The position where we want to add the Rdn
+     * @return the updated name (not a new one)
+     */
+    public Name add( int pos, Rdn newRdn )
+    {
+        rdns.add( newRdn );
+        
+        normalizeInternal();
+        toUpName();
+
+        return this;
+    }
+
+
     /**
      * Adds a single normalized RDN to the (leaf) end of this name.
      *
@@ -1424,7 +1451,7 @@
                 {
                     return new AttributeTypeAndValue( atav.getUpType(), oidNormalizer.getAttributeTypeOid(), 
                     		atav.getUpValue(),
-                    		oidNormalizer.getNormalizer().normalize( atav.getValue() ) );
+                    		oidNormalizer.getNormalizer().normalize( atav.getNormValue() ) );
 
                 }
                 else
@@ -1488,7 +1515,7 @@
             {
             	AttributeTypeAndValue val = atavs.next();
                 AttributeTypeAndValue newAtav = atavOidToName( val, oidsMap );
-                rdn.addAttributeTypeAndValue( val.getUpType(), newAtav.getNormType(), val.getUpValue(), newAtav.getValue() );
+                rdn.addAttributeTypeAndValue( val.getUpType(), newAtav.getNormType(), val.getUpValue(), newAtav.getNormValue() );
             }
 
         }
@@ -1709,24 +1736,15 @@
         // Should we store the byte[] ???
         
         // Write the RDNs. Is it's null, the number will be -1. 
-        if ( rdns == null )
-        {
-            out.writeInt( -1 );
-        }
-        else if ( rdns.size() == 0 )
-        {
-            out.writeInt( 0 );
-        }
-        else
+        out.writeInt( rdns.size() );
+
+        // Loop on the RDNs
+        for ( Rdn rdn:rdns )
         {
-            out.writeInt( rdns.size() );
-            
-            // Loop on the RDNs
-            for ( Rdn rdn:rdns )
-            {
-                out.writeObject( rdn );
-            }
+            out.writeObject( rdn );
         }
+        
+        out.flush();
     }
 
 
@@ -1761,28 +1779,12 @@
         
         // Read the RDNs. Is it's null, the number will be -1.
         int nbRdns = in.readInt();
+        rdns = new ArrayList<Rdn>( nbRdns );
         
-        switch ( nbRdns )
+        for ( int i = 0; i < nbRdns; i++ )
         {
-            case -1 :
-                // No RDN at all... 
-                rdns = null;
-                break;
-                
-            case 0 :
-                // No RDN, but we have to initialize the list
-                // Note : this may not be a different case than -1
-                rdns = new ArrayList<Rdn>();
-                break;
-                
-            default :
-                for ( int i = 0; i < nbRdns; i++ )
-                {
-                    Rdn rdn = (Rdn)in.readObject();
-                    rdns.add( rdn );
-                }
-            
-                break;
+            Rdn rdn = (Rdn)in.readObject();
+            rdns.add( rdn );
         }
     }
 }