You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2005/10/09 15:47:07 UTC

svn commit: r307428 - /directory/shared/ldap/trunk/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapDN.java

Author: elecharny
Date: Sun Oct  9 06:47:02 2005
New Revision: 307428

URL: http://svn.apache.org/viewcvs?rev=307428&view=rev
Log:
Complete rewriting of this class. It extends Name, and use an external parser
to analyse and construct a DN.

Modified:
    directory/shared/ldap/trunk/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapDN.java

Modified: directory/shared/ldap/trunk/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapDN.java
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/trunk/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapDN.java?rev=307428&r1=307427&r2=307428&view=diff
==============================================================================
--- directory/shared/ldap/trunk/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapDN.java (original)
+++ directory/shared/ldap/trunk/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapDN.java Sun Oct  9 06:47:02 2005
@@ -14,7 +14,7 @@
  *   limitations under the License.
  *
  */
-package org.apache.asn1new.ldap.codec.primitives;
+/*package org.apache.asn1new.ldap.codec.primitives;
 
 import java.io.UnsupportedEncodingException;
 
@@ -50,19 +50,19 @@
  * </p>
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- */
+ *
 public class LdapDN extends RelativeLdapDN
 {
     //~ Static fields/initializers -----------------------------------------------------------------
 
-    /** A null LdapDN */
+    /** A null LdapDN *
     public transient static final LdapDN EMPTY_STRING = new LdapDN();
 
     //~ Methods ------------------------------------------------------------------------------------
 
     /**
      * Construct an empty LdapDN object
-     */
+     *
     public LdapDN()
     {
         super(0, false);
@@ -78,10 +78,9 @@
      * 
      * @param bytes The byte buffer that contains the DN
      * @exception A DecoderException is thrown if the buffer does not contains a valid DN.
-     */
+     *
     public LdapDN( byte[] bytes ) throws DecoderException
     {
-
         if ( bytes == null || bytes.length == 0)
         {
             return;
@@ -125,5 +124,742 @@
         }
 
         setData(bytes);
+    }
+}
+*/
+
+package org.apache.asn1new.ldap.codec.primitives;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import javax.naming.InvalidNameException;
+import javax.naming.Name;
+
+import org.apache.asn1new.util.StringUtils;
+
+/**
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapDN extends LdapString implements Name
+{
+    /**
+     * Declares the Serial Version Uid.
+     * 
+     * @see <a href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always Declare Serial Version Uid</a>
+     */
+    private static final long serialVersionUID = 1L;
+
+    /** Value returned by the compareTo method if values are not equals */
+    public final static int NOT_EQUALS = -1;
+
+    /** Value returned by the compareTo method if values are equals */
+    public final static int EQUALS = 0;
+
+    //~ Static fields/initializers -----------------------------------------------------------------
+    /** The RDNs that are elements of the DN */
+    private List rdns = new ArrayList(5); 
+    
+    /** A null LdapDN */
+    public transient static final LdapDN EMPTY_LDAPDN = new LdapDN();
+
+    //~ Methods ------------------------------------------------------------------------------------
+
+    /**
+     * Construct an empty LdapDN object
+     */
+    public LdapDN()
+    {
+        super();
+    }
+    
+    /**
+     * Parse a String and checks that it is a valid DN <br>
+     * <p>
+     * &lt;distinguishedName&gt;     ::= &lt;name&gt; | e <br>
+     * &lt;name&gt;                ::= &lt;name-component&gt; &lt;name-components&gt; <br>
+     * &lt;name-components&gt;    ::= &lt;spaces&gt; &lt;separator&gt; &lt;spaces&gt; &lt;name-component&gt; &lt;name-components&gt; | e <br>
+     * </p>
+     * 
+     * @param bytes The byte buffer that contains the DN
+     * @exception A InvalidNameException is thrown if the buffer does not contains a valid DN.
+     */
+    public LdapDN( String string ) throws InvalidNameException
+    {
+        if ( StringUtils.isNotEmpty( string ) )
+        {
+            try
+            {
+                string.getBytes( "UTF-8" );
+            }
+            catch ( UnsupportedEncodingException uee )
+            {
+                throw new InvalidNameException( "The byte array is not an UTF-8 encoded Unicode String : " + uee.getMessage() );
+            }
+
+            DNParser.parse( string, rdns );
+        }
+        else
+        {
+            this.string = "";
+        }
+        
+        normalize();
+    }
+    
+    /**
+     * Parse a buffer and checks that it is a valid DN <br>
+     * <p>
+     * &lt;distinguishedName&gt;     ::= &lt;name&gt; | e <br>
+     * &lt;name&gt;                ::= &lt;name-component&gt; &lt;name-components&gt; <br>
+     * &lt;name-components&gt;    ::= &lt;spaces&gt; &lt;separator&gt; &lt;spaces&gt; &lt;name-component&gt; &lt;name-components&gt; | e <br>
+     * </p>
+     * 
+     * @param bytes The byte buffer that contains the DN
+     * @exception A InvalidNameException is thrown if the buffer does not contains a valid DN.
+     */
+    public LdapDN( byte[] bytes ) throws InvalidNameException
+    {
+        try
+        {
+            DNParser.parse( new String( bytes, "UTF-8" ), rdns );
+            this.string = toString();
+            normalize();
+        }
+        catch ( UnsupportedEncodingException uee )
+        {
+            throw new InvalidNameException( "The byte array is not an UTF-8 encoded Unicode String : " + uee.getMessage() );
+        }
+    }
+    
+
+    /**
+     * Normalize the DN by triming useless spaces and lowercasing names.
+     * @return a normalized form of the DN
+     */
+    private void normalize()
+    {
+        StringBuffer sb = new StringBuffer();
+        
+        if ( rdns == null )
+        {
+            string = "";
+        }
+        
+        Iterator elements = rdns.iterator();
+        boolean isFirst = true;
+        
+        while ( elements.hasNext() )
+        {
+            LdapRDN rdn = (LdapRDN)elements.next();
+            
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                sb.append(',');
+            }
+            
+            sb.append( rdn.toString() );
+        }
+
+        string = sb.toString();
+        
+        try
+        {
+            bytes = string.getBytes( "UTF-8" );
+        }
+        catch ( UnsupportedEncodingException uee )
+        {
+            // We can't reach this point
+        }
+    }
+    
+    /**
+     * Return the DN as a String
+     * @return A String representing the DN
+     */
+    public String toString()
+    {
+        if ( ( rdns == null ) || ( rdns.size() == 0 ) )
+        {
+            return "";
+        }
+        else
+        {
+            StringBuffer sb = new StringBuffer();
+            boolean isFirst = true;
+            
+            for ( int i = 0; i < rdns.size(); i++ )
+            {
+                if ( isFirst )
+                {
+                    isFirst = false;
+                }
+                else
+                {
+                    sb.append( ',' );
+                }
+                
+                sb.append( ( (LdapRDN)rdns.get( i ) ) );
+            }
+            
+            return sb.toString();
+        }
+    }
+
+    /**
+     * Get the initial DN (without normalization) 
+     * @return The DN as a String
+     */
+    public String getName()
+    {
+        return ( string == null ? "" : string );
+    }
+
+    /**
+     * Get the number of NameComponent conatained in this LdapDN
+     * 
+     * @return The number of NameComponent conatained in this LdapDN
+     */
+    public int size()
+    {
+        return rdns.size();
+    }
+    
+    /**
+     * Determines whether this name starts with a specified prefix.
+     * A name <tt>name</tt> is a prefix if it is equal to
+     * <tt>getPrefix(name.size())</tt>.
+     * 
+     * Be aware that for a specific DN like :
+     * 
+     * cn=xxx, ou=yyy
+     * 
+     * the startsWith method will retourn true with ou=yyy, and
+     * false with cn=xxx
+     *
+     * @param name the name to check
+     * @return  true if <tt>name</tt> is a prefix of this name, false otherwise
+     */
+    public boolean startsWith ( Name name )
+    {
+        if ( name instanceof LdapDN )
+        {
+            LdapDN nameDN = (LdapDN)name;
+            
+            if ( nameDN.size() == 0 )
+            {
+                return true;
+            }
+
+            if ( nameDN.size() > size() )
+            {
+                // The name is longer than the current LdapDN.
+                return false;
+            }
+            
+            // Ok, iterate through all the RDN of the name,
+            // starting a the end of the current list.
+            
+            for ( int i = nameDN.size() - 1; i >= 0; i-- )
+            {
+                LdapRDN nameRdn = (LdapRDN)(nameDN.rdns.get( nameDN.rdns.size() - i - 1 ));
+                LdapRDN ldapRdn = (LdapRDN)rdns.get( rdns.size() - i - 1 );
+                
+                if ( nameRdn.compareTo(ldapRdn) != 0 )
+                {
+                    return false;
+                }
+            }
+            
+            return true;
+        }
+        else
+        {
+            // We don't accept a Name which is not a LdapName
+            return name == null;
+        }
+    }
+
+    /**
+     * Determines whether this name ends with a specified suffix.
+     * A name <tt>name</tt> is a suffix if it is equal to
+     * <tt>getSuffix(size()-name.size())</tt>.
+     * 
+     * Be aware that for a specific DN like :
+     * 
+     * cn=xxx, ou=yyy
+     * 
+     * the endsWith method will retourn true with cn=xxx, and
+     * false with ou=yyy
+     *
+     * @param name the name to check
+     * @return  true if <tt>name</tt> is a suffix of this name, false otherwise
+     */
+    public boolean endsWith ( Name name )
+    {
+        if ( name instanceof LdapDN )
+        {
+            LdapDN nameDN = (LdapDN)name;
+            
+            if ( nameDN.size() == 0 )
+            {
+                return true;
+            }
+
+            if ( nameDN.size() > size() )
+            {
+                // The name is longer than the current LdapDN.
+                return false;
+            }
+            
+            // Ok, iterate through all the RDN of the name
+            for ( int i = 0; i < nameDN.size(); i++ )
+            {
+                LdapRDN nameRdn = (LdapRDN)(nameDN.rdns.get( i ));
+                LdapRDN ldapRdn = (LdapRDN)rdns.get( i );
+                
+                if ( nameRdn.compareTo(ldapRdn) != 0 )
+                {
+                    return false;
+                }
+            }
+            
+            return true;
+        }
+        else
+        {
+            // We don't accept a Name which is not a LdapName
+            return name == null;
+        }
+    }
+    
+    /**
+     * Determines whether this name is empty.
+     * An empty name is one with zero components.
+     *
+     * @return  true if this name is empty, false otherwise
+     */
+    public boolean isEmpty()
+    {
+        return ( rdns.size() == 0 );
+    }
+    
+    /**
+     * Retrieves a component of this name.
+     *
+     * @param posn
+     *      the 0-based index of the component to retrieve.
+     *      Must be in the range [0,size()).
+     * @return  the component at index posn
+     * @throws  ArrayIndexOutOfBoundsException
+     *      if posn is outside the specified range
+     */
+    public String get( int posn )
+    {
+        if ( rdns.size() == 0 )
+        {
+            return "";
+        }
+        else
+        {
+            LdapRDN rdn = (LdapRDN)rdns.get( rdns.size() - posn - 1 );
+        
+            return rdn.toString();
+        }
+    }
+    
+    /**
+     * Retrieves the components of this name as an enumeration
+     * of strings.  The effect on the enumeration of updates to
+     * this name is undefined.  If the name has zero components,
+     * an empty (non-null) enumeration is returned.
+     *
+     * @return  an enumeration of the components of this name, each a string
+     */
+    public Enumeration getAll()
+    {
+        /*
+         * Note that by accessing the name component using the get() method on
+         * the name rather than get() on the list we are reading components from
+         * right to left with increasing index values.  LdapName.get() does the
+         * index translation on m_list for us. 
+         */
+        return new Enumeration() 
+        {
+            private int pos ;
+
+            public boolean hasMoreElements()
+            {
+                return pos < rdns.size() ;
+            }
+
+            public Object nextElement()
+            {
+                if ( pos >= rdns.size() ) 
+                {
+                    throw new NoSuchElementException() ;
+                }
+
+                Object obj = get( pos ) ;
+                pos++ ;
+                return obj ;
+            }
+        };
+    }
+    
+    /**
+     * Creates a name whose components consist of a prefix of the
+     * components of this name.  Subsequent changes to
+     * this name will not affect the name that is returned and vice versa.
+     *
+     * @param posn
+     *      the 0-based index of the component at which to stop.
+     *      Must be in the range [0,size()].
+     * @return  a name consisting of the components at indexes in
+     *      the range [0,posn].
+     * @throws  ArrayIndexOutOfBoundsException
+     *      if posn is outside the specified range
+     */
+    public Name getPrefix( int posn )
+    {
+        if ( rdns.size() == 0 )
+        {
+            return EMPTY_LDAPDN;
+        }
+        
+        if ( ( posn < 0 ) || ( posn > rdns.size() ) )
+        {
+            throw new ArrayIndexOutOfBoundsException("The posn(" + posn + ") should be in the range [0, " + rdns.size() + "]");
+        }
+        
+        LdapDN newLdapDN = new LdapDN();
+        
+        for (int i = rdns.size() - posn; i < rdns.size(); i++ )
+        {
+            // Don't forget to clone the rdns !
+            newLdapDN.rdns.add( ( (LdapRDN)rdns.get( i ) ).clone() );
+        }
+
+        newLdapDN.normalize();
+        newLdapDN.string = newLdapDN.toString();
+        
+        return newLdapDN;
+    }
+
+    /**
+     * Creates a name whose components consist of a suffix of the
+     * components in this name.  Subsequent changes to
+     * this name do not affect the name that is returned and vice versa.
+     *
+     * @param posn
+     *      the 0-based index of the component at which to start.
+     *      Must be in the range [0,size()].
+     * @return  a name consisting of the components at indexes in
+     *      the range [posn,size()].  If posn is equal to 
+     *      size(), an empty name is returned.
+     * @throws  ArrayIndexOutOfBoundsException
+     *      if posn is outside the specified range
+     */
+    public Name getSuffix( int posn )
+    {
+        if ( rdns.size() == 0 )
+        {
+            return EMPTY_LDAPDN;
+        }
+        
+        if ( ( posn < 0 ) || ( posn > rdns.size() ) )
+        {
+            throw new ArrayIndexOutOfBoundsException("The posn(" + posn + ") should be in the range [0, " + rdns.size() + "]");
+        }
+        
+        LdapDN newLdapDN = new LdapDN();
+        
+        for (int i = 0; i < size() - posn; i++ )
+        {
+            // Don't forget to clone the rdns !
+            newLdapDN.rdns.add( ( (LdapRDN)rdns.get( i ) ).clone() );
+        }
+
+        newLdapDN.normalize();
+        newLdapDN.string = newLdapDN.toString();
+
+        return newLdapDN;
+    }
+    /**
+     * Adds the components of a name -- in order -- to the end of this name.
+     *
+     * @param suffix
+     *      the components to add
+     * @return  the updated name (not a new one)
+     *
+     * @throws  InvalidNameException if <tt>suffix</tt> is not a valid name,
+     *      or if the addition of the components would violate the syntax
+     *      rules of this name
+     */
+    public Name addAll( Name suffix ) throws InvalidNameException
+    {
+        addAll( rdns.size(), suffix );
+        
+        return this;
+    }
+
+    /**
+     * Adds the components of a name -- in order -- at a specified position
+     * within this name.
+     * Components of this name at or after the index of the first new
+     * component are shifted up (away from 0) to accommodate the new
+     * components.
+     *
+     * @param name
+     *      the components to add
+     * @param posn
+     *      the index in this name at which to add the new
+     *      components.  Must be in the range [0,size()].
+     * @return  the updated name (not a new one)
+     *
+     * @throws  ArrayIndexOutOfBoundsException
+     *      if posn is outside the specified range
+     * @throws  InvalidNameException if <tt>n</tt> is not a valid name,
+     *      or if the addition of the components would violate the syntax
+     *      rules of this name
+     */
+    public Name addAll(int posn, Name name) throws InvalidNameException
+    {
+        if (name instanceof LdapDN )
+        {
+            if ( ( name == null ) || ( name.size() == 0 ) )
+            {
+                return this;
+            }
+            
+            // Concatenate the rdns
+            rdns.addAll( size() - posn, ((LdapDN)name).rdns );
+
+            // Regenerate the normalized name and the original string
+            normalize();
+            
+            return this;
+        }
+        else
+        {
+            throw new InvalidNameException( "The suffix is not a LdapDN" );
+        }
+    }
+
+    /**
+     * Adds a single component to the end of this name.
+     *
+     * @param comp
+     *      the component to add
+     * @return  the updated name (not a new one)
+     *
+     * @throws  InvalidNameException if adding <tt>comp</tt> would violate
+     *      the syntax rules of this name
+     */
+    public Name add(String comp) throws InvalidNameException
+    {
+        // We have to parse the nameComponent which is given as an argument
+        LdapRDN newRdn = new LdapRDN( comp );
+        
+        rdns.add( 0, newRdn );
+        normalize();
+        
+        return this;
+    }
+
+    /**
+     * Adds a single component at a specified position within this name.
+     * Components of this name at or after the index of the new component
+     * are shifted up by one (away from index 0) to accommodate the new
+     * component.
+     *
+     * @param comp
+     *      the component to add
+     * @param posn
+     *      the index at which to add the new component.
+     *      Must be in the range [0,size()].
+     * @return  the updated name (not a new one)
+     *
+     * @throws  ArrayIndexOutOfBoundsException
+     *      if posn is outside the specified range
+     * @throws  InvalidNameException if adding <tt>comp</tt> would violate
+     *      the syntax rules of this name
+     */
+    public Name add(int posn, String comp) throws InvalidNameException
+    {
+        if ( ( posn < 0 ) || ( posn > size() ) )
+        {
+            throw new ArrayIndexOutOfBoundsException("The posn(" + posn + ") should be in the range [0, " + rdns.size() + "]"); 
+        }
+
+        // We have to parse the nameComponent which is given as an argument
+        LdapRDN newRdn = new LdapRDN( comp );
+        
+        int realPos = size() - posn;
+        rdns.add( realPos, newRdn );
+        normalize();
+        
+        return this;
+    }
+
+    /**
+     * Removes a component from this name.
+     * The component of this name at the specified position is removed.
+     * Components with indexes greater than this position
+     * are shifted down (toward index 0) by one.
+     *
+     * @param posn
+     *      the index of the component to remove.
+     *      Must be in the range [0,size()).
+     * @return  the component removed (a String)
+     *
+     * @throws  ArrayIndexOutOfBoundsException
+     *      if posn is outside the specified range
+     * @throws  InvalidNameException if deleting the component
+     *      would violate the syntax rules of the name
+     */
+    public Object remove(int posn) throws InvalidNameException
+    {
+        if ( rdns.size() == 0 )
+        {
+            return EMPTY_LDAPDN;
+        }
+        
+        if ( ( posn < 0 ) || ( posn >= rdns.size() ) )
+        {
+            throw new ArrayIndexOutOfBoundsException("The posn(" + posn + ") should be in the range [0, " + rdns.size() + "]");
+        }
+        
+        int realPos = size() - posn - 1;
+        LdapRDN rdn = (LdapRDN)rdns.remove( realPos );
+        normalize();
+        
+        return rdn;
+    }
+
+    /**
+     * Generates a new copy of this name.
+     * Subsequent changes to the components of this name will not
+     * affect the new copy, and vice versa.
+     *
+     * @return  a copy of this name
+     *
+     * @see Object#clone()
+     */
+    public Object clone()
+    {
+        try
+        {
+            LdapDN dn = (LdapDN)super.clone();
+            
+            for ( int i = 0; i < rdns.size(); i++ )
+            {
+                dn.rdns.set( i, ((LdapRDN)rdns.get( i ) ).clone() );
+            }
+            
+            return dn;
+        }
+        catch ( CloneNotSupportedException cnse )
+        {
+            throw new Error( "Assertion failure" );
+        }
+    }
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals( Object obj )
+    {
+        if ( obj instanceof String )
+        {
+            return toString().equals( obj ) ;
+        } 
+        else if ( obj instanceof LdapDN )
+        {
+            LdapDN name = ( LdapDN ) obj ;
+
+            if ( name.size() != this.size() )
+            {
+                return false ;
+            }
+
+            for ( int i = 0; i < size(); i++ ) 
+            {
+                if ( ( (LdapRDN)name.rdns.get( i ) ).compareTo( rdns.get( i ) ) == LdapRDN.NOT_EQUALS)
+                {
+                    return false;
+                }
+            }
+
+            // All components matched so we return true
+            return true ;
+        } 
+        else 
+        {
+            return false ;
+        }
+    }
+
+    /**
+     * Compares this name with another name for order.
+     * Returns a negative integer, zero, or a positive integer as this
+     * name is less than, equal to, or greater than the given name.
+     *
+     * <p> As with <tt>Object.equals()</tt>, the notion of ordering for names 
+     * depends on the class that implements this interface.
+     * For example, the ordering may be
+     * based on lexicographical ordering of the name components.
+     * Specific attributes of the name, such as how it treats case,
+     * may affect the ordering.  In general, two names of different
+     * classes may not be compared.
+     *
+     * @param   obj the non-null object to compare against.
+     * @return  a negative integer, zero, or a positive integer as this name
+     *      is less than, equal to, or greater than the given name
+     * @throws  ClassCastException if obj is not a <tt>Name</tt> of a
+     *      type that may be compared with this name
+     *
+     * @see Comparable#compareTo(Object)
+     */
+    public int compareTo(Object obj)
+    {
+        if ( obj instanceof LdapDN )
+        {
+            LdapDN ldapDN = (LdapDN)obj;
+            
+            if ( ldapDN.size() != size() )
+            {
+                return NOT_EQUALS;
+            }
+            
+            Iterator dn1Iter = rdns.iterator();
+            Iterator dn2Iter = ldapDN.rdns.iterator();
+            
+            while ( dn1Iter.hasNext() && dn2Iter.hasNext() )
+            {
+                LdapRDN rdn1 = (LdapRDN)dn1Iter.next();
+                LdapRDN rdn2 = (LdapRDN)dn2Iter.next();
+                
+                if ( rdn1.compareTo( rdn2 ) == LdapRDN.NOT_EQUALS )
+                {
+                    return NOT_EQUALS;
+                }
+            }
+            
+            return EQUALS;
+        }
+        else
+        {
+            return NOT_EQUALS;
+        }
     }
 }