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 2006/01/09 02:03:39 UTC
svn commit: r367149 [2/4] - in /directory/trunk/ldap-common/src:
main/java/org/apache/ldap/common/codec/
main/java/org/apache/ldap/common/codec/add/
main/java/org/apache/ldap/common/codec/bind/
main/java/org/apache/ldap/common/codec/compare/ main/java/...
Copied: directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/LdapDN.java (from r366272, directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/codec/util/LdapDN.java)
URL: http://svn.apache.org/viewcvs/directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/LdapDN.java?p2=directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/LdapDN.java&p1=directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/codec/util/LdapDN.java&r1=366272&r2=367149&rev=367149&view=diff
==============================================================================
--- directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/codec/util/LdapDN.java (original)
+++ directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/LdapDN.java Sun Jan 8 17:02:49 2006
@@ -14,142 +14,50 @@
* limitations under the License.
*
*/
-/*package org.apache.asn1new.ldap.codec.primitives;
-import java.io.UnsupportedEncodingException;
-
-import org.apache.asn1.codec.DecoderException;
-import org.apache.asn1new.util.StringTools;
-
-/**
- * This class parses a DN.
- *
- * The DN MUST respect this BNF grammar (as of RFC2253, par. 3, and RFC1779, fig. 1) <br>
- *
- * <p>
- *- <distinguishedName> ::= <name> | e <br>
- *- <name> ::= <name-component> <name-components> <br>
- *- <name-components> ::= <spaces> <separator> <spaces> <name-component> <name-components> | e <br>
- *- <name-component> ::= <attributeType> <spaces> '=' <spaces> <attributeValue> <attributeTypeAndValues> <br>
- *- <attributeTypeAndValues> ::= <spaces> '+' <spaces> <attributeType> <spaces> '=' <spaces> <attributeValue> <attributeTypeAndValues> | e <br>
- *- <attributeType> ::= [a-zA-Z] <keychars> | <oidPrefix> [0-9] <digits> <oids> | [0-9] <digits> <oids> <br>
- *- <keychars> ::= [a-zA-Z] <keychars> | [0-9] <keychars> | '-' <keychars> | e <br>
- *- <oidPrefix> ::= 'OID.' | 'oid.' | e <br>
- *- <oids> ::= '.' [0-9] <digits> <oids> | e <br>
- *- <attributeValue> ::= <pairs-or-strings> | '#' <hexstring> |'"' <quotechar-or-pairs> '"' <br>
- *- <pairs-or-strings> ::= '\' <pairchar> <pairs-or-strings> | <stringchar> <pairs-or-strings> | e <br>
- *- <quotechar-or-pairs> ::= <quotechar> <quotechar-or-pairs> | '\' <pairchar> <quotechar-or-pairs> | e <br>
- *- <pairchar> ::= ',' | '=' | '+' | '<' | '>' | '#' | ';' | '\' | '"' | [0-9a-fA-F] [0-9a-fA-F] <br>
- *- <hexstring> ::= [0-9a-fA-F] [0-9a-fA-F] <hexpairs> <br>
- *- <hexpairs> ::= [0-9a-fA-F] [0-9a-fA-F] <hexpairs> | e <br>
- *- <digits> ::= [0-9] <digits> | e <br>
- *- <stringchar> ::= [0x00-0xFF] - [,=+<>#;\"\n\r] <br>
- *- <quotechar> ::= [0x00-0xFF] - [\"] <br>
- *- <separator> ::= ',' | ';' <br>
- *- <spaces> ::= ' ' <spaces> | e <br>
- * </p>
- *
- * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- *
-public class LdapDN extends RelativeLdapDN
-{
- //~ Static fields/initializers -----------------------------------------------------------------
-
- /** A null LdapDN *
- public transient static final LdapDN EMPTY_STRING = new LdapDN();
-
- //~ Methods ------------------------------------------------------------------------------------
-
- /**
- * Construct an empty LdapDN object
- *
- public LdapDN()
- {
- super(0, false);
- }
-
- /**
- * Parse a buffer and checks that it is a valid DN <br>
- * <p>
- * <distinguishedName> ::= <name> | e <br>
- * <name> ::= <name-component> <name-components> <br>
- * <name-components> ::= <spaces> <separator> <spaces> <name-component> <name-components> | e <br>
- * </p>
- *
- * @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;
- }
-
- int pos = 0;
-
- // <name> ::= <name-component> <name-components>
- // <name-components> ::= <spaces> <separator> <spaces> <name-component> <name-components> | e
- if ( ( pos = parseNameComponent( bytes, pos ) ) != -1 )
- {
-
- do
- {
-
- if ( ( StringTools.isCharASCII( bytes, pos, ',' ) == false ) &&
- ( StringTools.isCharASCII( bytes, pos, ';' ) == false ) )
- {
-
- break;
- }
-
- bytes[pos] = ',';
- pos++;
-
- pos = parseSpaces( bytes, pos );
- }
- while ( ( pos = parseNameComponent( bytes, pos ) ) != -1 );
- }
- else
- {
- try
- {
- throw new DecoderException( "Bad DN : " + new String( bytes, "UTF-8" ) );
- }
- catch ( UnsupportedEncodingException uee )
- {
- throw new DecoderException( "Bad DN : " + StringTools.dumpBytes( bytes ) );
- }
-
- }
-
- setData(bytes);
- }
-}
-*/
-
-package org.apache.ldap.common.codec.util;
+package org.apache.ldap.common.name;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.NoSuchElementException;
import javax.naming.InvalidNameException;
import javax.naming.Name;
+import javax.naming.NamingException;
+import org.apache.ldap.common.codec.util.LdapString;
+import org.apache.ldap.common.codec.util.LdapStringEncodingException;
+import org.apache.ldap.common.name.Rdn;
+import org.apache.ldap.common.schema.OidNormalizer;
import org.apache.ldap.common.util.StringTools;
-import org.apache.ldap.common.codec.util.DNParser;
-
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
+ * The LdapDN class contains a DN (Distinguished Name). Its specification can be found in RFC 2253,
+ * "UTF-8 String Representation of Distinguished Names".
+ *
+ * We will store two representation of a DN :
+ * - a user Provider represeentation, which is the parsed String given by a user
+ * - an internal representation.
+ *
+ * A DN is formed of RDNs, in a specific order :
+ * RDN[n], RDN[n-1], ... RDN[1], RDN[0]
+ *
+ * It represents a tree, in which the root is the last RDN (RDN[0]) and the leaf is the
+ * first RDN (RDN[n]).
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
-public class LdapDN extends LdapString implements Name
+public class LdapDN /*extends LdapString*/ implements Name
{
+ /** The LoggerFactory used by this class */
+ private static Logger log = LoggerFactory.getLogger( LdapDN.class );
+
/**
* Declares the Serial Version Uid.
*
@@ -165,13 +73,19 @@
//~ Static fields/initializers -----------------------------------------------------------------
/** The RDNs that are elements of the DN */
- private List rdns = new ArrayList(5);
-
+ private List rdns = new ArrayList(5);
+
/** The user provided name */
private String upName;
-
+
+ /** The normalized name */
+ private String normName;
+
+ /** The bytes representation of the normName */
+ private byte[] bytes;
+
/** A null LdapDN */
- public transient static final LdapDN EMPTY_LDAPDN = new LdapDN();
+ public static final LdapDN EMPTY_LDAPDN = new LdapDN();
//~ Methods ------------------------------------------------------------------------------------
@@ -182,6 +96,48 @@
{
super();
upName = "";
+ normName = "";
+ }
+
+ /**
+ * Creates an ldap name using a list of NameComponents. Each NameComponent
+ * is a String
+ *
+ * @param a_list of String name components.
+ */
+ LdapDN( List list ) throws InvalidNameException
+ {
+ super();
+
+ if ( ( list != null ) && ( list.size() != 0 ) )
+ {
+ Iterator nameComponents = list.iterator();
+
+ while ( nameComponents.hasNext() )
+ {
+ String nameComponent = (String)nameComponents.next();
+ add( 0, nameComponent );
+ }
+ }
+ }
+
+ /**
+ * Creates an ldap name using a list of name components.
+ *
+ * @param nameComponents List of String name components.
+ */
+ LdapDN( Iterator nameComponents ) throws InvalidNameException
+ {
+ super();
+
+ if ( nameComponents != null )
+ {
+ while ( nameComponents.hasNext() )
+ {
+ String nameComponent = (String)nameComponents.next();
+ add( 0, nameComponent );
+ }
+ }
}
/**
@@ -195,30 +151,17 @@
* @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
+ public LdapDN( String upName ) throws InvalidNameException
{
- if ( StringTools.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
+ if ( StringTools.isNotEmpty( upName ) )
{
- this.string = "";
+ LdapDnParser.parseInternal( upName, rdns );
}
-
- normalize();
- upName = string;
+
+ // Stores the representations of a DN : internal (as a string and as a byte[]) and external.
+ normalize( upName );
}
-
+
/**
* Parse a buffer and checks that it is a valid DN <br>
* <p>
@@ -235,68 +178,80 @@
try
{
upName = new String( bytes, "UTF-8" );
- DNParser.parse( upName, rdns );
- string = toString();
-
- normalize();
+ LdapDnParser.parseInternal( upName, rdns );
+ this.normName = toNormName();
}
catch ( UnsupportedEncodingException uee )
{
+ log.error( "The byte array is not an UTF-8 encoded Unicode String : " + uee.getMessage() );
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()
+ private void normalize( String upName )
{
- StringBuffer sb = new StringBuffer();
-
- if ( rdns == null )
+ normName = toNormName();
+ this.upName = upName == null ? "" : upName ;
+ }
+
+ /**
+ * Build the normalized DN as a String,
+ * @return A String representing the normalized DN
+ */
+ public String toNormName()
+ {
+ if ( ( rdns == null ) || ( rdns.size() == 0 ) )
{
- string = "";
+ bytes = null;
+ return "";
}
-
- Iterator elements = rdns.iterator();
- boolean isFirst = true;
-
- while ( elements.hasNext() )
+ else
{
- LdapRDN rdn = (LdapRDN)elements.next();
-
- if ( isFirst )
- {
- isFirst = false;
- }
- else
+ StringBuffer sb = new StringBuffer();
+ boolean isFirst = true;
+
+ for ( int i = 0; i < rdns.size(); i++ )
{
- sb.append(',');
+ if ( isFirst )
+ {
+ isFirst = false;
+ }
+ else
+ {
+ sb.append( ',' );
+ }
+
+ sb.append( ( (Rdn)rdns.get( i ) ) );
}
-
- sb.append( rdn.toString() );
- }
-
- string = sb.toString();
-
- try
- {
- bytes = string.getBytes( "UTF-8" );
- }
- catch ( UnsupportedEncodingException uee )
- {
- // We can't reach this point
+
+ normName = sb.toString();
+ bytes = StringTools.getBytesUtf8( normName );
+
+ return normName;
}
}
-
+
/**
- * Return the normalized DN as a String,
+ * Return the normalized DN as a String. It returns the same value as the
+ * getNormName method
* @return A String representing the normalized DN
*/
public String toString()
{
+ return normName == null ? "" : normName;
+ }
+
+ /**
+ * Return the User Provided DN as a String,
+ * @return A String representing the User Provided DN
+ */
+ public String toUpName()
+ {
if ( ( rdns == null ) || ( rdns.size() == 0 ) )
{
return "";
@@ -305,7 +260,7 @@
{
StringBuffer sb = new StringBuffer();
boolean isFirst = true;
-
+
for ( int i = 0; i < rdns.size(); i++ )
{
if ( isFirst )
@@ -316,13 +271,122 @@
{
sb.append( ',' );
}
-
- sb.append( ( (LdapRDN)rdns.get( i ) ) );
+
+ sb.append(( (Rdn)rdns.get( i ) ).getUpName() );
}
-
+
return sb.toString();
}
}
+
+ /**
+ * Return the User Provided prefix representation of the DN starting at the posn position.
+ *
+ * If posn = 0, return an empty string.
+ *
+ * for DN : sn=smith, dc=apache, dc=org
+ *
+ * getUpname(0) -> ""
+ * getUpName(1) -> "dc=org"
+ * getUpname(3) -> "sn=smith, dc=apache, dc=org"
+ * getUpName(4) -> ArrayOutOfBoundException
+ *
+ * Warning ! The returned String is not exactly the user provided DN, as spaces
+ * before and after each RDNs have been trimmed.
+ *
+ * @param posn The starting position
+ * @return The truncated DN
+ */
+ private String getUpNamePrefix( int posn )
+ {
+ if ( posn == 0 )
+ {
+ return "";
+ }
+
+ if ( posn > rdns.size() )
+ {
+ String message = "Impossible to get the position " + posn + ", the DN only has " + rdns.size() + " RDNs";
+ log.error( message );
+ throw new ArrayIndexOutOfBoundsException( message );
+ }
+
+ int start = rdns.size() - posn;
+ StringBuffer sb = new StringBuffer();
+ boolean isFirst = true;
+
+ for ( int i = start; i < rdns.size(); i++ )
+ {
+ if ( isFirst )
+ {
+ isFirst = false;
+ }
+ else
+ {
+ sb.append( ',' );
+ }
+
+ sb.append( ( (Rdn)rdns.get( i ) ).getUpName() );
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Return the User Provided suffix representation of the DN starting at the posn position.
+ *
+ * If posn = 0, return an empty string.
+ *
+ * for DN : sn=smith, dc=apache, dc=org
+ *
+ * getUpname(0) -> "sn=smith, dc=apache, dc=org"
+ * getUpName(1) -> "sn=smith, dc=apache"
+ * getUpname(3) -> "sn=smith"
+ * getUpName(4) -> ""
+ *
+ * Warning ! The returned String is not exactly the user provided DN, as spaces
+ * before and after each RDNs have been trimmed.
+ *
+ * @param posn The starting position
+ * @return The truncated DN
+ */
+ private String getUpNameSuffix( int posn )
+ {
+ if ( posn > rdns.size() )
+ {
+ return "";
+ }
+
+ int end = rdns.size() - posn;
+ StringBuffer sb = new StringBuffer();
+ boolean isFirst = true;
+
+ for ( int i = 0; i < end; i++ )
+ {
+ if ( isFirst )
+ {
+ isFirst = false;
+ }
+ else
+ {
+ sb.append( ',' );
+ }
+
+ sb.append( ( (Rdn)rdns.get( i ) ).getUpName() );
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Gets the hashcode of the string representation of this name.
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode()
+ {
+ return upName.hashCode() ;
+ }
+
/**
* Get the initial DN (without normalization)
@@ -334,6 +398,15 @@
}
/**
+ * Get the initial DN (without normalization)
+ * @return The DN as a String
+ */
+ /*public String getNormName()
+ {
+ return ( normName == null ? "" : normName );
+ }*/
+
+ /**
* Get the number of NameComponent conatained in this LdapDN
*
* @return The number of NameComponent conatained in this LdapDN
@@ -342,7 +415,26 @@
{
return rdns.size();
}
-
+
+ /**
+ * Get the number of bytes necessary to store this DN
+ * @return A integer, which is the size of the UTF-8 byte array
+ */
+ public static int getNbBytes( Name dn )
+ {
+ LdapDN ldapDn = (LdapDN)dn;
+ return ldapDn.bytes == null ? 0 : ldapDn.bytes.length;
+ }
+
+ /**
+ * Get an UTF-8 representation of the normalized form of the DN
+ * @return A byte[] representation of the DN
+ */
+ public static byte[] getBytes( Name dn )
+ {
+ return ((LdapDN)dn).bytes;
+ }
+
/**
* Determines whether this name starts with a specified prefix.
* A name <tt>name</tt> is a prefix if it is equal to
@@ -363,7 +455,7 @@
if ( name instanceof LdapDN )
{
LdapDN nameDN = (LdapDN)name;
-
+
if ( nameDN.size() == 0 )
{
return true;
@@ -374,21 +466,21 @@
// 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 );
-
+ Rdn nameRdn = (Rdn)(nameDN.rdns.get( nameDN.rdns.size() - i - 1 ));
+ Rdn ldapRdn = (Rdn)rdns.get( rdns.size() - i - 1 );
+
if ( nameRdn.compareTo(ldapRdn) != 0 )
{
return false;
}
}
-
+
return true;
}
else
@@ -418,7 +510,7 @@
if ( name instanceof LdapDN )
{
LdapDN nameDN = (LdapDN)name;
-
+
if ( nameDN.size() == 0 )
{
return true;
@@ -429,19 +521,19 @@
// 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 );
-
+ Rdn nameRdn = (Rdn)(nameDN.rdns.get( i ));
+ Rdn ldapRdn = (Rdn)rdns.get( i );
+
if ( nameRdn.compareTo(ldapRdn) != 0 )
{
return false;
}
}
-
+
return true;
}
else
@@ -450,7 +542,7 @@
return name == null;
}
}
-
+
/**
* Determines whether this name is empty.
* An empty name is one with zero components.
@@ -461,7 +553,7 @@
{
return ( rdns.size() == 0 );
}
-
+
/**
* Retrieves a component of this name.
*
@@ -480,19 +572,61 @@
}
else
{
- LdapRDN rdn = (LdapRDN)rdns.get( rdns.size() - posn - 1 );
-
+ Rdn rdn = (Rdn)rdns.get( rdns.size() - posn - 1 );
+
return rdn.toString();
}
}
-
+
+ /**
+ * 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 Rdn getRdn( int posn )
+ {
+ if ( rdns.size() == 0 )
+ {
+ return null;
+ }
+ else
+ {
+ Rdn rdn = (Rdn)rdns.get( rdns.size() - posn - 1 );
+
+ return rdn;
+ }
+ }
+
+ /**
+ * Retrieves all the components of this name.
+ *
+ * @return All the components
+ */
+ public List getRdns()
+ {
+ List newRdns = new ArrayList();
+
+ // We will clone the list, to avoid user modifications
+ for ( int i = 0; i < rdns.size(); i++ )
+ {
+ newRdns.add( i, ((Rdn)rdns.get( i ) ).clone() );
+ }
+
+ return newRdns;
+ }
+
/**
* 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
+ * @return an enumeration of the components of this name, each as string
*/
public Enumeration getAll()
{
@@ -502,7 +636,7 @@
* right to left with increasing index values. LdapName.get() does the
* index translation on m_list for us.
*/
- return new Enumeration()
+ return new Enumeration()
{
private int pos ;
@@ -513,18 +647,59 @@
public Object nextElement()
{
- if ( pos >= rdns.size() )
+ if ( pos >= rdns.size() )
{
+ log.error( "Exceeded number of elements in the current object" );
throw new NoSuchElementException() ;
}
- Object obj = get( pos ) ;
+ Object obj = rdns.get( rdns.size() - pos - 1 );
pos++ ;
- return obj ;
+ return obj.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, as Rdn
+ */
+ public Enumeration getAllRdn()
+ {
+ /*
+ * 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() )
+ {
+ log.error( "Exceeded number of elements in the current object" );
+ throw new NoSuchElementException() ;
+ }
+ Object obj = rdns.get( rdns.size() - pos - 1 );
+ pos++ ;
+ return obj ;
+ }
+ };
+ }
+
/**
* Creates a name whose components consist of a prefix of the
* components of this name. Subsequent changes to
@@ -544,24 +719,25 @@
{
return EMPTY_LDAPDN;
}
-
+
if ( ( posn < 0 ) || ( posn > rdns.size() ) )
{
- throw new ArrayIndexOutOfBoundsException("The posn(" + posn + ") should be in the range [0, " + rdns.size() + "]");
+ String message = "The posn(" + posn + ") should be in the range [0, " + rdns.size() + "]";
+ log.error( message );
+ throw new ArrayIndexOutOfBoundsException( message );
}
-
+
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.rdns.add( ( (Rdn)rdns.get( i ) ).clone() );
}
- newLdapDN.normalize();
- newLdapDN.string = newLdapDN.toString();
- newLdapDN.upName = newLdapDN.string;
-
+ newLdapDN.normName = newLdapDN.toNormName();
+ newLdapDN.upName = getUpNamePrefix( posn );
+
return newLdapDN;
}
@@ -585,26 +761,28 @@
{
return EMPTY_LDAPDN;
}
-
+
if ( ( posn < 0 ) || ( posn > rdns.size() ) )
{
- throw new ArrayIndexOutOfBoundsException("The posn(" + posn + ") should be in the range [0, " + rdns.size() + "]");
+ String message = "The posn(" + posn + ") should be in the range [0, " + rdns.size() + "]";
+ log.error( message );
+ throw new ArrayIndexOutOfBoundsException( message );
}
-
+
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.rdns.add( ( (Rdn)rdns.get( i ) ).clone() );
}
- newLdapDN.normalize();
- newLdapDN.string = newLdapDN.toString();
- newLdapDN.upName = newLdapDN.string;
+ newLdapDN.normName = newLdapDN.toNormName();
+ newLdapDN.upName = getUpNameSuffix( posn );
return newLdapDN;
}
+
/**
* Adds the components of a name -- in order -- to the end of this name.
*
@@ -619,7 +797,7 @@
public Name addAll( Name suffix ) throws InvalidNameException
{
addAll( rdns.size(), suffix );
-
+
return this;
}
@@ -651,19 +829,18 @@
{
return this;
}
-
+
// Concatenate the rdns
rdns.addAll( size() - posn, ((LdapDN)name).rdns );
// Regenerate the normalized name and the original string
- normalize();
-
- upName = toString();
-
+ normalize( toUpName() );
+
return this;
}
else
{
+ log.error( "Not a valid LdapDN suffix : " + name );
throw new InvalidNameException( "The suffix is not a LdapDN" );
}
}
@@ -681,12 +858,10 @@
public Name add(String comp) throws InvalidNameException
{
// We have to parse the nameComponent which is given as an argument
- LdapRDN newRdn = new LdapRDN( comp );
-
+ Rdn newRdn = new Rdn( comp );
+
rdns.add( 0, newRdn );
- normalize();
-
- upName = toString();
+ normalize( toUpName() );
return this;
}
@@ -713,18 +888,19 @@
{
if ( ( posn < 0 ) || ( posn > size() ) )
{
- throw new ArrayIndexOutOfBoundsException("The posn(" + posn + ") should be in the range [0, " + rdns.size() + "]");
+ String message = "The posn(" + posn + ") should be in the range [0, " + rdns.size() + "]";
+ log.error( message );
+ throw new ArrayIndexOutOfBoundsException( message );
}
// We have to parse the nameComponent which is given as an argument
- LdapRDN newRdn = new LdapRDN( comp );
-
+ Rdn newRdn = new Rdn( comp );
+
int realPos = size() - posn;
rdns.add( realPos, newRdn );
- normalize();
-
- upName = toString();
-
+
+ normalize( toUpName() );
+
return this;
}
@@ -750,18 +926,19 @@
{
return EMPTY_LDAPDN;
}
-
+
if ( ( posn < 0 ) || ( posn >= rdns.size() ) )
{
- throw new ArrayIndexOutOfBoundsException("The posn(" + posn + ") should be in the range [0, " + rdns.size() + "]");
+ String message = "The posn(" + posn + ") should be in the range [0, " + rdns.size() + "]";
+ log.error ( message );
+ throw new ArrayIndexOutOfBoundsException( message );
}
-
+
int realPos = size() - posn - 1;
- LdapRDN rdn = (LdapRDN)rdns.remove( realPos );
- normalize();
-
- upName = toString();
-
+ Rdn rdn = (Rdn)rdns.remove( realPos );
+
+ normalize( toUpName() );
+
return rdn;
}
@@ -779,17 +956,19 @@
try
{
LdapDN dn = (LdapDN)super.clone();
-
+ dn.rdns = new ArrayList();
+
for ( int i = 0; i < rdns.size(); i++ )
{
- dn.rdns.set( i, ((LdapRDN)rdns.get( i ) ).clone() );
+ dn.rdns.add( i, ((Rdn)rdns.get( i ) ).clone() );
}
-
+
return dn;
}
catch ( CloneNotSupportedException cnse )
{
- throw new Error( "Assertion failure" );
+ log.error( "The clone operation has failed" );
+ throw new Error( "Assertion failure : cannot clone the object" );
}
}
@@ -800,8 +979,8 @@
{
if ( obj instanceof String )
{
- return toString().equals( obj ) ;
- }
+ return normName.equals( obj ) ;
+ }
else if ( obj instanceof LdapDN )
{
LdapDN name = ( LdapDN ) obj ;
@@ -811,9 +990,9 @@
return false ;
}
- for ( int i = 0; i < size(); i++ )
+ for ( int i = 0; i < size(); i++ )
{
- if ( ( (LdapRDN)name.rdns.get( i ) ).compareTo( rdns.get( i ) ) == LdapRDN.NOT_EQUALS)
+ if ( ( (Rdn)name.rdns.get( i ) ).compareTo( rdns.get( i ) ) != 0)
{
return false;
}
@@ -821,8 +1000,8 @@
// All components matched so we return true
return true ;
- }
- else
+ }
+ else
{
return false ;
}
@@ -854,31 +1033,220 @@
if ( obj instanceof LdapDN )
{
LdapDN ldapDN = (LdapDN)obj;
-
+
if ( ldapDN.size() != size() )
{
- return NOT_EQUALS;
+ return size() - ldapDN.size();
}
- Iterator dn1Iter = rdns.iterator();
- Iterator dn2Iter = ldapDN.rdns.iterator();
-
- while ( dn1Iter.hasNext() && dn2Iter.hasNext() )
+ for ( int i = rdns.size(); i > 0; i-- )
{
- LdapRDN rdn1 = (LdapRDN)dn1Iter.next();
- LdapRDN rdn2 = (LdapRDN)dn2Iter.next();
-
- if ( rdn1.compareTo( rdn2 ) == LdapRDN.NOT_EQUALS )
+ Rdn rdn1 = (Rdn) rdns.get( i - 1 );
+ Rdn rdn2 = (Rdn) ldapDN.rdns.get( i - 1 );
+ int res = rdn1.compareTo( rdn2 );
+
+ if ( res != 0 )
{
- return NOT_EQUALS;
+ return res;
}
}
-
+
return EQUALS;
}
else
{
- return NOT_EQUALS;
+ return 1;
}
}
+
+ private static AttributeTypeAndValue atavOidToName( AttributeTypeAndValue atav, Map oids ) throws InvalidNameException, NamingException
+ {
+ String type = StringTools.trim( atav.getType() );
+
+ if ( StringTools.isNotEmpty( StringTools.lowerCase( type ) ) )
+ {
+ OidNormalizer oidNormalizer = (OidNormalizer)oids.get( type );
+
+ if ( oidNormalizer != null )
+ {
+ return new AttributeTypeAndValue( oidNormalizer.getName(),
+ (String)oidNormalizer.getNormalizer().normalize( atav.getValue() ) );
+
+ }
+ else
+ {
+ // We don't have a normalizer for this OID : just do nothing.
+ return atav;
+ }
+ }
+ else
+ {
+ // The type is empty : this is not possible...
+ log.error( "Empty type not allowed in a DN" );
+ throw new InvalidNameException( "Empty type not allowed in a DN" );
+ }
+
+ }
+
+ /**
+ * Transform a RDN by changing the value to its OID counterpart and normalizing
+ * the value accordingly to its type.
+ * @param rdn The RDN to modify
+ * @param oids The map of all existing oids and normalizer
+ * @throws InvalidNameException If
+ * @throws NamingException
+ */
+ private static void rdnOidToName( Rdn rdn, Map oids ) throws InvalidNameException, NamingException
+ {
+ if ( rdn.getNbAtavs() > 1 )
+ {
+ // We have more than one ATAV for this RDN. We will loop on all ATAVs
+ Rdn rdnCopy = (Rdn)rdn.clone();
+ rdn.clear();
+
+ Iterator atavs = rdnCopy.iterator();
+
+ while ( atavs.hasNext() )
+ {
+ Object val = atavs.next();
+ AttributeTypeAndValue newAtav = atavOidToName( (AttributeTypeAndValue)val, oids );
+ rdn.addAttributeTypeAndValue( newAtav.getType(), newAtav.getValue() );
+ }
+
+
+ }
+ else
+ {
+ String type = StringTools.trim( rdn.getType() );
+
+ if ( StringTools.isNotEmpty( StringTools.lowerCase( type ) ) )
+ {
+ OidNormalizer oidNormalizer = (OidNormalizer)oids.get( type );
+
+ if ( oidNormalizer != null )
+ {
+ Rdn rdnCopy = (Rdn)rdn.clone();
+ rdn.clear();
+
+ rdn.addAttributeTypeAndValue( oidNormalizer.getName(),
+ (String)oidNormalizer.getNormalizer().normalize( rdnCopy.getValue() ) );
+
+ }
+ else
+ {
+ // We don't have a normalizer for this OID : just do nothing.
+ return;
+ }
+ }
+ else
+ {
+ // The type is empty : this is not possible...
+ log.error( "We should not have an empty DN" );
+ throw new InvalidNameException( "Empty type not allowed in a DN" );
+ }
+ }
+ }
+
+ /**
+ * Change the internal DN, using the first alias instead of oids or other aliases.
+ * As we still have the UP name of each RDN, we will be able to provide both
+ * representation of the DN.
+ *
+ * example :
+ *
+ * dn: 2.5.4.3=People, dc=example, domainComponent=com
+ *
+ * will be transformed to :
+ *
+ * cn=People, dc=example, dc=com
+ *
+ * because 2.5.4.3 is the OID for cn and dc is the first alias
+ * of the couple of aliases (dc, domaincomponent).
+ *
+ * This is really important do have such a representation, as 'cn' and 'commonname'
+ * share the same OID.
+ *
+ * @param dn The DN to transform
+ * @param oids The mapping between names and oids.
+ * @return A normalized form of the DN
+ * @throws InvalidNameException If the DN is invalid
+ */
+ public static Name normalize( Name dn, Map oids ) throws InvalidNameException, NamingException
+ {
+ if ( ( dn == null ) || ( dn.size() == 0 ) || ( oids== null ) || ( oids.size() == 0 ) )
+ {
+ return dn;
+ }
+
+ LdapDN newDn = (LdapDN)dn.clone();
+
+ Enumeration rdns = newDn.getAllRdn();
+
+ // Loop on all RDNs
+ while ( rdns.hasMoreElements() )
+ {
+ Rdn rdn = (Rdn)rdns.nextElement();
+ String upName = rdn.getUpName();
+ rdnOidToName( rdn, oids );
+ rdn.normalizeString();
+ rdn.setUpName( upName );
+ }
+
+ newDn.normalize( newDn.upName );
+
+ return newDn;
+ }
+
+ public static Name normalize( Name dn ) throws InvalidNameException, NamingException
+ {
+ return normalize( dn, DnOidContainer.getOids() );
+ }
+
+ /**
+ * Substitute OIDs and aliases for the simplest alias
+ * @param tlv The TLV which contains the data
+ * @return A simple attribute
+ * @throws LdapStringEncodingException If the attribute is not valid
+ */
+ public static LdapString normalizeAttribute( byte[] data ) throws LdapStringEncodingException
+ {
+ LdapString type = new LdapString( data );
+
+ OidNormalizer oidNormalizer = (OidNormalizer)DnOidContainer.getOids().get( type.getString() );
+
+ if ( oidNormalizer != null )
+ {
+ type = new LdapString( StringTools.getBytesUtf8( oidNormalizer.getName() ) );
+ }
+
+ return type;
+ }
+
+ /*
+ public Name toLdapName() throws InvalidNameException
+ {
+ Name name = new LdapName();
+
+ Enumeration rdns = getAll();
+
+ while ( rdns.hasMoreElements() )
+ {
+ name.add( (String)rdns.nextElement() );
+ }
+
+ return name;
+ }
+
+ public LdapDN( LdapName name ) throws InvalidNameException
+ {
+ Name newName = new LdapDN();
+
+ Enumeration comps = name.getAll();
+
+ while ( comps.hasMoreElements() )
+ {
+ newName.add( (String)comps.nextElement() );
+ }
+ }
+ */
}
Propchange: directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/LdapDN.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/LdapDnParser.java
URL: http://svn.apache.org/viewcvs/directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/LdapDnParser.java?rev=367149&view=auto
==============================================================================
--- directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/LdapDnParser.java (added)
+++ directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/LdapDnParser.java Sun Jan 8 17:02:49 2006
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.ldap.common.name;
+
+import java.util.List;
+
+import javax.naming.InvalidNameException;
+import javax.naming.Name;
+
+import org.apache.ldap.common.util.DNUtils;
+import org.apache.ldap.common.util.StringTools;
+
+import javax.naming.NameParser ;
+
+/**
+ * This class parses a DN.
+ *
+ * The DN MUST respect this BNF grammar (as of RFC2253, par. 3, and RFC1779, fig. 1) <br>
+ *
+ * <p>
+ *- <distinguishedName> ::= <name> | e <br>
+ *- <name> ::= <name-component> <name-components> <br>
+ *- <name-components> ::= <spaces> <separator> <spaces> <name-component> <name-components> | e <br>
+ *- <name-component> ::= <attributeType> <spaces> '=' <spaces> <attributeValue> <attributeTypeAndValues> <br>
+ *- <attributeTypeAndValues> ::= <spaces> '+' <spaces> <attributeType> <spaces> '=' <spaces> <attributeValue> <attributeTypeAndValues> | e <br>
+ *- <attributeType> ::= [a-zA-Z] <keychars> | <oidPrefix> [0-9] <digits> <oids> | [0-9] <digits> <oids> <br>
+ *- <keychars> ::= [a-zA-Z] <keychars> | [0-9] <keychars> | '-' <keychars> | e <br>
+ *- <oidPrefix> ::= 'OID.' | 'oid.' | e <br>
+ *- <oids> ::= '.' [0-9] <digits> <oids> | e <br>
+ *- <attributeValue> ::= <pairs-or-strings> | '#' <hexstring> |'"' <quotechar-or-pairs> '"' <br>
+ *- <pairs-or-strings> ::= '\' <pairchar> <pairs-or-strings> | <stringchar> <pairs-or-strings> | e <br>
+ *- <quotechar-or-pairs> ::= <quotechar> <quotechar-or-pairs> | '\' <pairchar> <quotechar-or-pairs> | e <br>
+ *- <pairchar> ::= ',' | '=' | '+' | '<' | '>' | '#' | ';' | '\' | '"' | [0-9a-fA-F] [0-9a-fA-F] <br>
+ *- <hexstring> ::= [0-9a-fA-F] [0-9a-fA-F] <hexpairs> <br>
+ *- <hexpairs> ::= [0-9a-fA-F] [0-9a-fA-F] <hexpairs> | e <br>
+ *- <digits> ::= [0-9] <digits> | e <br>
+ *- <stringchar> ::= [0x00-0xFF] - [,=+<>#;\"\n\r] <br>
+ *- <quotechar> ::= [0x00-0xFF] - [\"] <br>
+ *- <separator> ::= ',' | ';' <br>
+ *- <spaces> ::= ' ' <spaces> | e <br>
+ * </p>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapDnParser implements NameParser
+{
+ private static LdapDnParser instance = new LdapDnParser();
+
+ /**
+ * A private constructor. It's useless, as this object is totally stateless,
+ * but we need to expose a NameParser.
+ *
+ */
+ private LdapDnParser()
+ {
+ }
+
+ /**
+ * Get a reference to the NameParser. Needed to be compliant with the JNDI API
+ * @return An instance of the NameParser
+ */
+ public static NameParser getNameParser()
+ {
+ return instance;
+ }
+
+ /**
+ * Parse a DN
+ * @param dn The DN to be parsed
+ * @param rdns The list that will contain the RDNs
+ * @throws InvalidNameException If the DN is invalid
+ */
+ public static void parseInternal( String dn, List rdns ) throws InvalidNameException
+ {
+ // We won't decode the LdapDN using the bytes.
+ char[] chars = dn.trim().toCharArray();
+
+ if ( chars.length == 0 )
+ {
+ // We have an empty DN, just get out of the function.
+ return;
+ }
+
+ int pos = 0;
+ Rdn rdn = new Rdn();
+
+ // <name> ::= <name-component> <name-components>
+ // <name-components> ::= <spaces> <separator> <spaces> <name-component> <name-components> | e
+ if ( ( pos = RdnParser.parse( chars, pos, rdn ) ) != DNUtils.PARSING_ERROR )
+ {
+ do
+ {
+ rdns.add( rdn.clone() );
+ rdn.clear();
+
+ if ( ( StringTools.isCharASCII( chars, pos, ',' ) == false ) &&
+ ( StringTools.isCharASCII( chars, pos, ';' ) == false ) )
+ {
+
+ break;
+ }
+
+ chars[pos] = ',';
+ pos++;
+
+ //pos = StringUtils.trimLeft( chars, pos );
+ }
+ while ( ( pos = RdnParser.parse( chars, pos, rdn ) ) != DNUtils.PARSING_ERROR );
+ }
+ else
+ {
+ throw new InvalidNameException( "Bad DN : " + new String( chars ) );
+ }
+ }
+
+ /**
+ * Parse a String and return a LdapDN if the String is a valid DN
+ * @param dn The DN to parse
+ * @return A LdapDN
+ * @throws InvalidNameException If the String is not a valid DN
+ */
+ public Name parse( String dn ) throws InvalidNameException
+ {
+ return new LdapDN( dn );
+ }
+}
Modified: directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/LdapName.java
URL: http://svn.apache.org/viewcvs/directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/LdapName.java?rev=367149&r1=367148&r2=367149&view=diff
==============================================================================
--- directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/LdapName.java (original)
+++ directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/LdapName.java Sun Jan 8 17:02:49 2006
@@ -32,11 +32,9 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.NoSuchElementException;
import org.apache.ldap.common.util.NamespaceTools;
-import org.apache.ldap.common.util.StringTools;
import javax.naming.InvalidNameException;
import javax.naming.Name;
@@ -929,6 +927,7 @@
}
+ /*
public static LdapName toOidName( LdapName dn, Map oids ) throws InvalidNameException
{
if ( ( dn == null ) || ( dn.size() == 0 ) )
@@ -985,5 +984,6 @@
return newDn;
}
+ */
}
Added: directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/Rdn.java
URL: http://svn.apache.org/viewcvs/directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/Rdn.java?rev=367149&view=auto
==============================================================================
--- directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/Rdn.java (added)
+++ directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/Rdn.java Sun Jan 8 17:02:49 2006
@@ -0,0 +1,1081 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.ldap.common.name;
+
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeSet;
+
+import javax.naming.InvalidNameException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+
+import org.apache.commons.collections.MultiHashMap;
+import org.apache.ldap.common.util.StringTools;
+
+/**
+ * This class store the name-component part or the following BNF grammar (as of RFC2253, par. 3,
+ * and RFC1779, fig. 1) : <br>
+ * - <name-component> ::= <attributeType> <spaces> '=' <spaces> <attributeValue> <attributeTypeAndValues> <br>
+ * - <attributeTypeAndValues> ::= <spaces> '+' <spaces> <attributeType> <spaces> '=' <spaces> <attributeValue> <attributeTypeAndValues> | e <br>
+ * - <attributeType> ::= [a-zA-Z] <keychars> | <oidPrefix> [0-9] <digits> <oids> | [0-9] <digits> <oids> <br>
+ * - <keychars> ::= [a-zA-Z] <keychars> | [0-9] <keychars> | '-' <keychars> | e <br>
+ * - <oidPrefix> ::= 'OID.' | 'oid.' | e <br>
+ * - <oids> ::= '.' [0-9] <digits> <oids> | e <br>
+ * - <attributeValue> ::= <pairs-or-strings> | '#' <hexstring> |'"' <quotechar-or-pairs> '"' <br>
+ * - <pairs-or-strings> ::= '\' <pairchar> <pairs-or-strings> | <stringchar> <pairs-or-strings> | e <br>
+ * - <quotechar-or-pairs> ::= <quotechar> <quotechar-or-pairs> | '\' <pairchar> <quotechar-or-pairs> | e <br>
+ * - <pairchar> ::= ',' | '=' | '+' | '<' | '>' | '#' | ';' | '\' | '"' | [0-9a-fA-F] [0-9a-fA-F] <br>
+ * - <hexstring> ::= [0-9a-fA-F] [0-9a-fA-F] <hexpairs> <br>
+ * - <hexpairs> ::= [0-9a-fA-F] [0-9a-fA-F] <hexpairs> | e <br>
+ * - <digits> ::= [0-9] <digits> | e <br>
+ * - <stringchar> ::= [0x00-0xFF] - [,=+<>#;\"\n\r] <br>
+ * - <quotechar> ::= [0x00-0xFF] - [\"] <br>
+ * - <separator> ::= ',' | ';' <br>
+ * - <spaces> ::= ' ' <spaces> | e <br>
+ *<br>
+ * A RDN is a part of a DN. It can be composed of many types, as in the RDN
+ * following RDN :<br>
+ * ou=value + cn=other value<br>
+ * <br>
+ * or
+ * <br>
+ * ou=value + ou=another value<br>
+ * <br>
+ * In this case, we have to store an 'ou' and a 'cn' in the RDN.<br>
+ * <br>
+ * The types are case insensitive. <br>
+ * Spaces before and after types and values are not stored.<br>
+ * Spaces before and after '+' are not stored.<br>
+ * <br>
+ * Thus, we can consider that the following RDNs are equals :<br>
+ * <br>
+ * 'ou=test 1'<br>
+ * ' ou=test 1'<br>
+ * 'ou =test 1'<br>
+ * 'ou= test 1'<br>
+ * 'ou=test 1 '<br>
+ * ' ou = test 1 '<br>
+ * <br>
+ * So are the following :<br>
+ * <br>
+ * 'ou=test 1+cn=test 2'<br>
+ * 'ou = test 1 + cn = test 2'<br>
+ * ' ou =test 1+ cn =test 2 ' <br>
+ * 'cn = test 2 +ou = test 1'<br>
+ * <br>
+ * but the following are not equal :<br>
+ * 'ou=test 1' <br>
+ * 'ou=test 1'<br>
+ * because we have more than one spaces inside the value.<br>
+ * <br>
+ *
+ * The Rdn is composed of one or more AttributeTypeAndValue (atav)
+ * Those atavs are ordered in the alphabetical natural order :
+ * a < b < c ... < z
+ *
+ * As the type are not case sensitive, we can say that a = A
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ *
+ */
+public class Rdn implements Cloneable, Comparable, Serializable
+{
+ /**
+ * 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;
+
+ /** The User Provided RDN */
+ private String upName = null;
+
+ /** The normalized RDN */
+ private String string = null;
+
+ /**
+ * Stores all couple type = value. We may have more than one type,
+ * if the '+' character appears in the AttributeTypeAndValue. This is
+ * a TreeSet, because we want the ATAVs to be sorted.
+ * An atav may contain more than one value. In this case, the values
+ * are String stored in a List.
+ */
+ private TreeSet atavs = null;
+
+ /**
+ * We also keep a set of types, in order to use manipulations. A type is
+ * connected with the atav it represents.
+ */
+ private Map atavTypes = new MultiHashMap();
+
+ /**
+ * A simple AttributeTypeAndValue is used to store the Rdn for the simple
+ * case where we only have a single type=value. This will be 99.99%
+ * the case. This avoids the creation of a HashMap.
+ */
+ private AttributeTypeAndValue atav = null;
+
+ /** The number of atavs. We store this number here to avoid complex
+ * manipulation of atav and atavs */
+ private int nbAtavs = 0;
+
+ /** CompareTo() results */
+ public static final int UNDEFINED = Integer.MAX_VALUE;
+ public static final int SUPERIOR = 1;
+ public static final int INFERIOR = -1;
+ public static final int EQUALS = 0;
+
+ /**
+ * A empty constructor.
+ */
+ public Rdn()
+ {
+ // Don't waste space... This is not so often we have multiple
+ // name-components in a RDN... So we won't initialize the Map and the treeSet.
+ upName = "";
+ string = "";
+ }
+
+ /**
+ * A constructor that parse a String RDN
+ *
+ * @param rdn The String containing the RDN to parse
+ * @throws InvalidNameException If the RDN is invalid
+ */
+ public Rdn( String rdn ) throws InvalidNameException
+ {
+ if ( StringTools.isNotEmpty( rdn ) )
+ {
+ try
+ {
+ // Check that the String is a Valid UTF-8 string
+ rdn.getBytes( "UTF-8" );
+ }
+ catch ( UnsupportedEncodingException uee )
+ {
+ throw new InvalidNameException( "The byte array is not an UTF-8 encoded Unicode String : " + uee.getMessage() );
+ }
+
+ // Parse the string. The Rdn will be updated.
+ RdnParser.parse( rdn, this );
+ normalizeString();
+ // The upName is set by the RdnParser
+ }
+ else
+ {
+ upName = "";
+ string = "";
+ }
+ }
+
+ /**
+ * A constructor that parse a RDN from a byte array. This method
+ * is called when whe get a LdapMessage which contains a byte
+ * array representing the ASN.1 RelativeRDN
+ *
+ * @param rdn The byte array containing the RDN to parse
+ * @throws InvalidNameException If the RDN is invalid
+ */
+
+ public Rdn( byte[] bytes ) throws InvalidNameException
+ {
+ try
+ {
+ RdnParser.parse( new String( bytes, "UTF-8" ), this );
+ normalizeString();
+ // The upName is set by the RdnParser
+ }
+ catch ( UnsupportedEncodingException uee )
+ {
+ throw new InvalidNameException( "The byte array is not an UTF-8 encoded Unicode String : " + uee.getMessage() );
+ }
+ }
+
+ /**
+ * A constructor that constructs a RDN from a type and a value.
+ *
+ * Constructs an Rdn from the given attribute type and value. The string attribute
+ * values are not interpretted as RFC 2253 formatted RDN strings. That is, the
+ * values are used literally (not parsed) and assumed to be unescaped.
+ *
+ * @param type The type of the RDN
+ * @param value The value of the RDN
+ * @throws InvalidNameException If the RDN is invalid
+ */
+ public Rdn( String type, String value ) throws InvalidNameException
+ {
+ super();
+
+ addAttributeTypeAndValue( type, value );
+
+ upName = type + '=' + value;
+ normalizeString();
+ }
+
+ /**
+ * Constructs an Rdn from the given rdn. The contents of the rdn are simply
+ * copied into the newly created
+ *
+ * @param rdn The non-null Rdn to be copied.
+ */
+ public Rdn( Rdn rdn )
+ {
+ super();
+ nbAtavs = rdn.getNbAtavs();
+ this.string = new String( rdn.string );
+ this.upName = new String( rdn.getUpName() );
+
+ switch ( rdn.getNbAtavs() )
+ {
+ case 0 :
+ return;
+
+ case 1 :
+ this.atav = (AttributeTypeAndValue)rdn.atav.clone();
+ return;
+
+ default :
+ // We must duplicate the treeSet and the hashMap
+ Iterator iter = rdn.atavs.iterator();
+
+ atavs = new TreeSet();
+ atavTypes = new MultiHashMap();
+
+ while ( iter.hasNext() )
+ {
+ AttributeTypeAndValue currentAtav = (AttributeTypeAndValue)iter.next();
+ atavs.add( currentAtav.clone() );
+ atavTypes.put( currentAtav.getType(), currentAtav );
+ }
+ }
+ }
+
+ /**
+ * Transform the external representation of the current RDN
+ * to an internal normalized form where :
+ * - types are trimmed and lowercased
+ * - values are trimmed and lowercased
+ */
+ // WARNING : The protection level is left unspecified intentionnaly.
+ // We need this method to be visible from the DnParser class, but not
+ // from outside this package.
+ /* Unspecified protection */ void normalizeString()
+ {
+ switch ( nbAtavs )
+ {
+ case 0 :
+ // An empty RDN
+ string = "";
+ break;
+
+ case 1:
+ // We have a single AttributeTypeAndValue
+ // We will trim and lowercase type and value.
+ string = StringTools.lowerCase( StringTools.trim( atav.getType() ) ) +
+ '=' + StringTools.trim( atav.getValue() );
+ break;
+
+ default :
+ // We have more than one AttributeTypeAndValue
+ StringBuffer sb = new StringBuffer();
+
+ Iterator elems = atavs.iterator();
+ boolean isFirst = true;
+
+ while ( elems.hasNext() )
+ {
+ AttributeTypeAndValue ata = (AttributeTypeAndValue)elems.next();
+
+ if ( isFirst )
+ {
+ isFirst = false;
+ }
+ else
+ {
+ sb.append( '+' );
+ }
+
+
+ sb.append( ata.normalize() );
+ }
+
+ string = sb.toString();
+ break;
+ }
+ }
+
+ /**
+ * Add a AttributeTypeAndValue to the current RDN
+ *
+ * @param type The type of the added RDN.
+ * @param value The value of the added RDN
+ * @throws InvalidNameException If the RDN is invalid
+ */
+ // WARNING : The protection level is left unspecified intentionnaly.
+ // We need this method to be visible from the DnParser class, but not
+ // from outside this package.
+ /* Unspecified protection */ void addAttributeTypeAndValue( String type, String value) throws InvalidNameException
+ {
+ // First, let's normalize the type
+ String normalizedType = StringTools.lowerCase( StringTools.trim( type ) );
+ String normalizedValue = StringTools.trim( value );
+
+ switch ( nbAtavs )
+ {
+ case 0 :
+ // This is the first AttributeTypeAndValue. Just stores it.
+ atav = new AttributeTypeAndValue( normalizedType, normalizedValue );
+ nbAtavs = 1;
+ atavTypes.put( normalizedType, atav );
+ return;
+
+ case 1 :
+ // We already have an atav. We have to put it in the HashMap
+ // before adding a new one.
+ // First, create the HashMap,
+ atavs = new TreeSet();
+
+ // and store the existing AttributeTypeAndValue into it.
+ atavs.add( atav );
+
+ atav = null;
+
+ // Now, fall down to the commmon case
+ // NO BREAK !!!
+
+ default :
+ // add a new AttributeTypeAndValue
+ AttributeTypeAndValue newAtav = new AttributeTypeAndValue( normalizedType, normalizedValue );
+ atavs.add( newAtav );
+ atavTypes.put( normalizedType, newAtav );
+
+ nbAtavs++;
+ break;
+
+ }
+ }
+
+ /**
+ * Clear the RDN, removing all the AttributeTypeAndValues.
+ */
+ public void clear()
+ {
+ atav = null;
+ atavs = null;
+ atavTypes.clear();
+ nbAtavs = 0;
+ string = "";
+ upName = "";
+ }
+
+ /**
+ * Get the Value of the AttributeTypeAndValue which type is given as an argument.
+ *
+ * @param type The type of the NameArgument
+ * @return The Value to be returned, or null if none found.
+ */
+ public String getValue( String type ) throws InvalidNameException
+ {
+ // First, let's normalize the type
+ String normalizedType = StringTools.lowerCase( StringTools.trim( type ) );
+
+ switch ( nbAtavs )
+ {
+ case 0:
+ return "";
+
+ case 1:
+ if ( StringTools.equals( atav.getType(), normalizedType ) )
+ {
+ return atav.getValue();
+ }
+ else
+ {
+ return "";
+ }
+
+ default :
+ if ( atavTypes.containsKey( normalizedType ) )
+ {
+ Object obj = atavTypes.get( normalizedType );
+
+ if ( obj instanceof AttributeTypeAndValue )
+ {
+ return ((AttributeTypeAndValue)obj).getValue();
+ }
+ else if ( obj instanceof List )
+ {
+ StringBuffer sb = new StringBuffer();
+ boolean isFirst = true;
+
+ for ( int i = 0; i < ((List)obj).size(); i++ )
+ {
+ AttributeTypeAndValue elem = (AttributeTypeAndValue)((List)obj).get( i );
+
+ if ( isFirst )
+ {
+ isFirst = false;
+ }
+ else
+ {
+ sb.append( ',' );
+ }
+
+ sb.append( elem.getValue() );
+ }
+
+ return sb.toString();
+ }
+ else
+ {
+ throw new InvalidNameException( "Bad object stored in the RDN" );
+ }
+ }
+ else
+ {
+ return "";
+ }
+ }
+ }
+
+ /**
+ * Get the AttributeTypeAndValue which type is given as an argument.
+ * If we have more than one value associated with the type, we will
+ * return only the first one.
+ *
+ * @param type The type of the NameArgument to be returned
+ * @return The AttributeTypeAndValue, of null if none is found.
+ */
+ public AttributeTypeAndValue getAttributeTypeAndValue( String type )
+ {
+ // First, let's normalize the type
+ String normalizedType = StringTools.lowerCase( StringTools.trim( type ) );
+
+ switch ( nbAtavs )
+ {
+ case 0:
+ return null;
+
+ case 1:
+ if ( atav.getType().equals( normalizedType ) )
+ {
+ return atav;
+ }
+ else
+ {
+ return null;
+ }
+
+ default :
+ if ( atavTypes.containsKey( normalizedType ) )
+ {
+ return (AttributeTypeAndValue)atavTypes.get( normalizedType );
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * 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 Iterator iterator()
+ {
+ if ( nbAtavs == 1 )
+ {
+ return new Iterator()
+ {
+ private boolean hasMoreElement = true;
+
+ public boolean hasNext()
+ {
+ return hasMoreElement ;
+ }
+
+ public Object next()
+ {
+ Object obj = atav ;
+ hasMoreElement = false ;
+ return obj ;
+ }
+
+ public void remove()
+ {
+
+ }
+ };
+ }
+ else
+ {
+ return atavs.iterator();
+ }
+ }
+
+ /**
+ * Clone the Rdn
+ */
+ public Object clone()
+ {
+ try
+ {
+ Rdn rdn = (Rdn)super.clone();
+
+ // The AttributeTypeAndValue is immutable. We won't clone it
+
+ switch ( rdn.getNbAtavs() )
+ {
+ case 0 :
+ break;
+
+ case 1 :
+ rdn.atav = (AttributeTypeAndValue)this.atav.clone();
+ rdn.atavTypes = new MultiHashMap();
+ rdn.atavTypes.put( rdn.atav.getType(), rdn.atav );
+ break;
+
+ default :
+ // We must duplicate the treeSet and the hashMap
+ rdn.atavTypes = new MultiHashMap();
+ rdn.atavs = new TreeSet();
+
+ Iterator iter = this.atavs.iterator();
+
+ while ( iter.hasNext() )
+ {
+ AttributeTypeAndValue currentAtav = (AttributeTypeAndValue)iter.next();
+ rdn.atavs.add( currentAtav.clone() );
+ rdn.atavTypes.put( currentAtav.getType(), currentAtav );
+ }
+
+ break;
+ }
+
+ return rdn;
+ }
+ catch ( CloneNotSupportedException cnse )
+ {
+ throw new Error( "Assertion failure" );
+ }
+ }
+
+ /**
+ * Compares two RDNs. They are equals if :
+ * - their have the same number of NC (AttributeTypeAndValue)
+ * - each ATAVs are equals
+ * - comparizon of type are done case insensitive
+ * - each value is equel, case sensitive
+ * - Order of ATAV is not important
+ *
+ * If the RDNs are not equals, a positive number is returned if the
+ * first RDN is greated, negative otherwise
+ * @param object
+ * @return 0 if both rdn are equals. -1 if the current RDN is inferior, 1 if
+ * teh current Rdn is superioir, UNDIFIED otherwise.
+ */
+ public int compareTo( Object object )
+ {
+ if ( object instanceof Rdn )
+ {
+ Rdn rdn = (Rdn)object;
+
+ if ( rdn == null )
+ {
+ return SUPERIOR;
+ }
+
+ if ( rdn.nbAtavs != nbAtavs )
+ {
+ // We don't have the same number of ATAVs. The Rdn which
+ // has the higher number of Atav is the one which is
+ // superior
+ return nbAtavs - rdn.nbAtavs;
+ }
+
+ switch ( nbAtavs )
+ {
+ case 0:
+ return EQUALS;
+
+ case 1:
+ return atav.compareTo( rdn.atav );
+
+ default :
+ // We have more than one value. We will
+ // go through all of them.
+ Iterator keys = atavs.iterator();
+
+ while ( keys.hasNext() )
+ {
+ AttributeTypeAndValue current = (AttributeTypeAndValue)keys.next();
+ String type = current.getType();
+
+ if ( rdn.atavTypes.containsKey( type ) )
+ {
+ List atavLocalList = (List)atavTypes.get( type );
+ List atavParamList = (List)rdn.atavTypes.get( type );
+
+ if ( atavLocalList.size() == 1 )
+ {
+ // We have only one ATAV
+ AttributeTypeAndValue atavLocal = (AttributeTypeAndValue)atavLocalList.get(0);
+ AttributeTypeAndValue atavParam = (AttributeTypeAndValue)atavParamList.get(0);
+
+ return atavLocal.compareTo( atavParam );
+ }
+ else
+ {
+ // We have to verify that each value of the first list are present in
+ // the second list
+ Iterator atavLocals = atavLocalList.iterator();
+
+ while ( atavLocals.hasNext() )
+ {
+ AttributeTypeAndValue atavLocal = (AttributeTypeAndValue)atavLocals.next();
+
+ Iterator atavParams = atavParamList.iterator();
+ boolean found = false;
+
+ while ( atavParams.hasNext() )
+ {
+ AttributeTypeAndValue atavParam = (AttributeTypeAndValue)atavParams.next();
+
+ if ( atavLocal.compareTo( atavParam ) == EQUALS )
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if ( !found )
+ {
+ // The ATAV does not exist in the second RDN
+ return SUPERIOR;
+ }
+ }
+ }
+
+ return EQUALS;
+ }
+ else
+ {
+ // We can't find an atav in the rdn : the current one is superior
+ return SUPERIOR;
+ }
+ }
+
+ return EQUALS;
+ }
+ }
+ else
+ {
+ return object != null ? UNDEFINED : SUPERIOR;
+ }
+ }
+
+ /**
+ * Returns a String representation of the RDN
+ */
+ public String toString()
+ {
+ return string;
+ }
+
+ /**
+ * Returns a String representation of the RDN
+ */
+ public String getUpName()
+ {
+ return upName;
+ }
+
+ /**
+ * Set the User Provided Name
+ */
+ public void setUpName( String upName )
+ {
+ this.upName = upName;
+ }
+
+ /**
+ * @return Returns the nbAtavs.
+ */
+ public int getNbAtavs()
+ {
+ return nbAtavs;
+ }
+
+ /**
+ * Return the unique AttributeTypeAndValue, or the first one of we have more than one
+ * @return The first AttributeTypeAndValue of this RDN
+ */
+ public AttributeTypeAndValue getAtav()
+ {
+ switch ( nbAtavs )
+ {
+ case 0 :
+ return null;
+
+ case 1 :
+ return atav;
+
+ default :
+ return (AttributeTypeAndValue)atavs.first();
+ }
+ }
+
+ /**
+ * Return the type, or the first one of we have more than one (the lowest)
+ * @return The first type of this RDN
+ */
+ public String getType()
+ {
+ switch ( nbAtavs )
+ {
+ case 0 :
+ return null;
+
+ case 1 :
+ return atav.getType();
+
+ default :
+ return ((AttributeTypeAndValue)atavs.first()).getType();
+ }
+ }
+
+ /**
+ * Return the value, or the first one of we have more than one (the lowest)
+ * @return The first value of this RDN
+ */
+ public String getValue()
+ {
+ switch ( nbAtavs )
+ {
+ case 0 :
+ return null;
+
+ case 1 :
+ return atav.getValue();
+
+ default :
+ return ((AttributeTypeAndValue)atavs.first()).getValue();
+ }
+ }
+
+ /**
+ * Compares the specified Object with this Rdn for equality. Returns true
+ * if the given object is also a Rdn and the two Rdns represent the same
+ * attribute type and value mappings. The order of components in multi-valued
+ * Rdns is not significant.
+ * @param rdn Rdn to be compared for equality with this Rdn
+ * @return true if the specified object is equal to this Rdn
+ */
+ public boolean equals( Object rdn )
+ {
+ if ( this == rdn )
+ {
+ return true;
+ }
+
+ if ( !(rdn instanceof Rdn ) )
+ {
+ return false;
+ }
+
+ return compareTo( (Rdn)rdn ) == EQUALS;
+ }
+
+ /**
+ * Returns the hash code of this RDN. Two RDNs that are equal (according
+ * to the equals method) will have the same hash code.
+ *
+ * @returnAn int representing the hash code of this Rdn
+ */
+ public int hashcode()
+ {
+ // We compute the hashcode using the string, which is a
+ // normalized form of a rdn. unescapeValue
+ return 37*17 + string.hashCode();
+ }
+
+ /**
+ * Get the number of Attribute type and value of this Rdn
+ * @return The number of ATAVs in this Rdn
+ */
+ public int size()
+ {
+ return nbAtavs;
+ }
+
+ /**
+ * Transform the Rdn into an javax.naming.directory.Attributes
+ *
+ * @return An attributes structure containing all the ATAVs
+ */
+ public Attributes toAttributes()
+ {
+ Attributes attributes = new BasicAttributes();
+
+ Iterator types = atavTypes.keySet().iterator();
+
+ while ( types.hasNext() )
+ {
+ String type = (String)types.next();
+ List values = (List)atavTypes.get( type );
+
+ Attribute attribute = new BasicAttribute( type, true );
+
+ Iterator iterValues = values.iterator();
+
+ while ( iterValues.hasNext() )
+ {
+ AttributeTypeAndValue value = (AttributeTypeAndValue)iterValues.next();
+
+ attribute.add( value.getValue() );
+ }
+
+ attributes.put( attribute );
+ }
+
+ return attributes;
+ }
+
+ /**
+ * Unescape the given string according to RFC 2253
+ * If in <string> form, a LDAP string representation asserted value can
+ * be obtained by replacing (left-to-right, non-recursively) each <pair>
+ * appearing in the <string> as follows:
+ * replace <ESC><ESC> with <ESC>;
+ * replace <ESC><special> with <special>;
+ * replace <ESC><hexpair> with the octet indicated by the <hexpair>
+ *
+ * If in <hexstring> form, a BER representation can be obtained from
+ * converting each <hexpair> of the <hexstring> to the octet indicated by
+ * the <hexpair>
+ *
+ * @param value The value to be unescaped
+ * @return Returns a string value as a String, and a binary value as a byte array.
+ * @throws IllegalArgumentException - When an Illegal value is provided.
+ */
+ public static Object unescapeValue( String value ) throws IllegalArgumentException
+ {
+ if ( StringTools.isEmpty( value ) )
+ {
+ return "";
+ }
+
+ char[] chars = value.toCharArray();
+
+ if ( chars[0] == '#' )
+ {
+ if ( chars.length == 1 )
+ {
+ // The value is only containing a #
+ return StringTools.EMPTY_BYTES;
+ }
+
+ if ( ( chars.length % 2 ) != 1 )
+ {
+ throw new IllegalArgumentException("This value is not in hex form, we have an odd number of hex chars" );
+ }
+
+ // HexString form
+ byte[] hexValue = new byte[ (chars.length - 1)/2];
+ int pos = 0;
+
+ for ( int i = 1; i < chars.length; i += 2 )
+ {
+ if ( StringTools.isHex( chars, i ) && StringTools.isHex( chars, i + 1 ) )
+ {
+ hexValue[ pos++ ] = (byte)((StringTools.HEX_VALUE[ chars[i] ] << 4) + StringTools.HEX_VALUE[ chars[i + 1] ]);
+ }
+ else
+ {
+ throw new IllegalArgumentException("This value is not in hex form" );
+ }
+ }
+
+ return hexValue;
+ }
+ else
+ {
+ boolean escaped = false;
+ boolean isHex = false;
+ byte pair = -1;
+ int pos = 0;
+
+ byte[] bytes = new byte[ chars.length * 6];
+
+ for ( int i = 0; i < chars.length; i++ )
+ {
+ if ( escaped )
+ {
+ escaped = false;
+
+ switch ( chars[i] )
+ {
+ case '\\' :
+ case '"' :
+ case '+' :
+ case ',' :
+ case ';' :
+ case '<' :
+ case '>' :
+ case '#' :
+ case '=' :
+ case ' ' :
+ bytes[pos++] = (byte)chars[i];
+ break;
+
+ default :
+ if ( StringTools.isHex( chars, i ) )
+ {
+ isHex = true;
+ pair = ((byte)(StringTools.HEX_VALUE[ chars[i] ] << 4));
+ }
+ }
+ }
+ else
+ {
+ if ( isHex )
+ {
+ if ( StringTools.isHex( chars, i ) )
+ {
+ pair += (byte)StringTools.HEX_VALUE[ chars[i] ];
+ bytes[pos++] = pair;
+ }
+ }
+ else
+ {
+ switch ( chars[i] )
+ {
+ case '\\' :
+ escaped = true;
+ break;
+
+ // We must not have a special char
+ // Specials are : '"', '+', ',', ';', '<', '>', ' ', '#' and '='
+ case '"' :
+ case '+' :
+ case ',' :
+ case ';' :
+ case '<' :
+ case '>' :
+ case '#' :
+ case '=' :
+ case ' ' :
+ throw new IllegalArgumentException( "Unescaped special characters are not allowed" );
+
+ default :
+ byte[] result = StringTools.charToBytes( chars[i] );
+
+ for ( int j = 0; j < result.length; j++ )
+ {
+ bytes[pos++] = result[j];
+ }
+ }
+ }
+ }
+ }
+
+ return StringTools.utf8ToString( bytes, pos );
+ }
+ }
+
+ /**
+ * Transform a value in a String, accordingly to RFC 2253
+ *
+ * @param attrValue The attribute value to be escaped
+ * @return The escaped string value.
+ */
+ public static String escapeValue( Object attrValue)
+ {
+ if (StringTools.isEmpty( (byte[])attrValue) )
+ {
+ return "";
+ }
+
+ String value = StringTools.utf8ToString( (byte[])attrValue );
+
+ char[] chars = value.toCharArray();
+ char[] newChars = new char[chars.length * 3];
+ int pos = 0;
+
+ for ( int i = 0; i < chars.length; i++ )
+ {
+ switch ( chars[i] )
+ {
+ case ' ' :
+ case '"' :
+ case '#' :
+ case '+' :
+ case ',' :
+ case ';' :
+ case '=' :
+ case '<' :
+ case '>' :
+ case '\\' :
+ newChars[pos++] = '\\';
+ newChars[pos++] = chars[i];
+ break;
+
+ case 0x7F :
+ newChars[pos++] = '\\';
+ newChars[pos++] = '7';
+ newChars[pos++] = 'F';
+ break;
+
+ case 0x00 : case 0x01 : case 0x02 : case 0x03 :
+ case 0x04 : case 0x05 : case 0x06 : case 0x07 :
+ case 0x08 : case 0x09 : case 0x0A : case 0x0B :
+ case 0x0C : case 0x0D : case 0x0E : case 0x0F :
+ newChars[pos++] = '\\';
+ newChars[pos++] = '0';
+ newChars[pos++] = StringTools.dumpHex( (byte)(chars[i] & 0x0F) );
+ break;
+
+ case 0x10 : case 0x11 : case 0x12 : case 0x13 :
+ case 0x14 : case 0x15 : case 0x16 : case 0x17 :
+ case 0x18 : case 0x19 : case 0x1A : case 0x1B :
+ case 0x1C : case 0x1D : case 0x1E : case 0x1F :
+ newChars[pos++] = '\\';
+ newChars[pos++] = '1';
+ newChars[pos++] = StringTools.dumpHex( (byte)(chars[i] & 0x0F) );
+ break;
+
+
+ default :
+ newChars[pos++] = chars[i];
+
+ }
+ }
+
+ return new String( newChars, 0, pos);
+ }
+}
Propchange: directory/trunk/ldap-common/src/main/java/org/apache/ldap/common/name/Rdn.java
------------------------------------------------------------------------------
svn:executable = *