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 2009/08/06 01:00:19 UTC
svn commit: r801455 -
/directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/name/Rdn.java
Author: elecharny
Date: Wed Aug 5 23:00:18 2009
New Revision: 801455
URL: http://svn.apache.org/viewvc?rev=801455&view=rev
Log:
Removed ^M
Modified:
directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/name/Rdn.java
Modified: directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/name/Rdn.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/name/Rdn.java?rev=801455&r1=801454&r2=801455&view=diff
==============================================================================
--- directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/name/Rdn.java (original)
+++ directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/name/Rdn.java Wed Aug 5 23:00:18 2009
@@ -117,825 +117,830 @@
* href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always
* Declare Serial Version Uid</a>
*/
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 1L;
- /** The User Provided RDN */
- private String upName = null;
+ /** The User Provided RDN */
+ private String upName = null;
- /** The normalized RDN */
- private String normName = null;
+ /** The normalized RDN */
+ private String normName = null;
- /** The starting position of this RDN in the given string from which
- * we have extracted the upName */
- private int start;
-
- /** The length of this RDN upName */
- private int length;
-
- /**
- * 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 Set<AttributeTypeAndValue> atavs = null;
+ /** The starting position of this RDN in the given string from which
+ * we have extracted the upName */
+ private int start;
- /**
- * We also keep a set of types, in order to use manipulations. A type is
- * connected with the atav it represents.
- *
- * Note : there is no Generic available classes in commons-collection...
- */
- @SuppressWarnings({"unchecked"})
- private Map<String, AttributeTypeAndValue> atavTypes = new MultiValueMap();
+ /** The length of this RDN upName */
+ private int length;
- /**
- * We keep the type for a single valued RDN, to avoid the creation of an HashMap
- */
- private String atavType = 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 Set<AttributeTypeAndValue> atavs = null;
- /**
- * 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.
- */
- protected AttributeTypeAndValue atav = null;
+ /**
+ * We also keep a set of types, in order to use manipulations. A type is
+ * connected with the atav it represents.
+ *
+ * Note : there is no Generic available classes in commons-collection...
+ */
+ @SuppressWarnings(
+ { "unchecked" })
+ private Map<String, AttributeTypeAndValue> atavTypes = new MultiValueMap();
- /**
- * The number of atavs. We store this number here to avoid complex
- * manipulation of atav and atavs
- */
- private int nbAtavs = 0;
+ /**
+ * We keep the type for a single valued RDN, to avoid the creation of an HashMap
+ */
+ private String atavType = null;
- /** CompareTo() results */
- public static final int UNDEFINED = Integer.MAX_VALUE;
+ /**
+ * 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.
+ */
+ protected AttributeTypeAndValue atav = null;
- /** Constant used in comparisons */
- public static final int SUPERIOR = 1;
+ /**
+ * The number of atavs. We store this number here to avoid complex
+ * manipulation of atav and atavs
+ */
+ private int nbAtavs = 0;
- /** Constant used in comparisons */
- public static final int INFERIOR = -1;
+ /** CompareTo() results */
+ public static final int UNDEFINED = Integer.MAX_VALUE;
- /** Constant used in comparisons */
- public static final int EQUAL = 0;
+ /** Constant used in comparisons */
+ public static final int SUPERIOR = 1;
+ /** Constant used in comparisons */
+ public static final int INFERIOR = -1;
- /**
- * 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 = "";
- normName = "";
- }
+ /** Constant used in comparisons */
+ public static final int EQUAL = 0;
- /**
- * A constructor that parse a String representing a RDN.
- *
- * @param rdn The String containing the RDN to parse
- * @throws InvalidNameException If the RDN is invalid
- */
- public Rdn( String rdn ) throws InvalidNameException
- {
- start = 0;
-
- if ( StringTools.isNotEmpty( rdn ) )
- {
- // Parse the string. The Rdn will be updated.
- RdnParser.parse( rdn, this );
-
- // create the internal normalized form
- // and store the user provided form
- normalize();
- upName = rdn;
- length = rdn.length();
- }
- else
- {
- upName = "";
- normName = "";
- length = 0;
- }
- }
-
-
- /**
- * 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 interpreted as RFC 2253 formatted RDN strings. That is,
- * the values are used literally (not parsed) and assumed to be un-escaped.
- *
- * @param upType The user provided type of the RDN
- * @param upValue The user provided value of the RDN
- * @param normType The normalized provided type of the RDN
- * @param normValue The normalized provided value of the RDN
- * @throws InvalidNameException If the RDN is invalid
- */
- public Rdn( String upType, String normType, String upValue, String normValue ) throws InvalidNameException
- {
- addAttributeTypeAndValue( upType, normType,
- new ClientStringValue( upValue),
- new ClientStringValue( normValue ) );
-
- upName = upType + '=' + upValue;
- start = 0;
- length = upName.length();
- // create the internal normalized form
- normalize();
- }
-
-
- /**
- * A constructor that constructs a RDN from a type, a position and a length.
- *
- * @param start The starting point for this RDN in the user provided DN
- * @param length The RDN's length
- * @param upName The user provided name
- * @param normName the normalized name
- */
- /* No protection */ Rdn( int start, int length, String upName, String normName )
- {
- this.start = 0;
- this.length = length;
- this.upName = upName;
- this.normName = normName;
- }
-
-
- /**
- * 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.
- */
- @SuppressWarnings({"unchecked"})
- public Rdn( Rdn rdn )
- {
- nbAtavs = rdn.getNbAtavs();
- this.normName = rdn.normName;
- this.upName = rdn.getUpName();
- this.start = rdn.start;
- this.length = rdn.length;
-
- switch ( rdn.getNbAtavs() )
- {
- case 0:
- return;
-
- case 1:
- this.atav = ( AttributeTypeAndValue ) rdn.atav.clone();
- return;
-
- default:
- // We must duplicate the treeSet and the hashMap
- atavs = new TreeSet<AttributeTypeAndValue>();
- atavTypes = new MultiValueMap();
-
- for ( AttributeTypeAndValue currentAtav:rdn.atavs )
- {
- atavs.add( (AttributeTypeAndValue)currentAtav.clone() );
- atavTypes.put( currentAtav.getNormType(), currentAtav );
- }
-
- return;
- }
- }
-
-
- /**
- * 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 normalize()
- {
- switch ( nbAtavs )
- {
- case 0:
- // An empty RDN
- normName = "";
- break;
-
- case 1:
- // We have a single AttributeTypeAndValue
- // We will trim and lowercase type and value.
- if ( !atav.getNormValue().isBinary() )
- {
- normName = atav.getNormalizedValue();
- }
- else
- {
- normName = atav.getNormType() + "=#" + StringTools.dumpHexPairs( atav.getNormValue().getBytes() );
- }
-
- break;
-
- default:
- // We have more than one AttributeTypeAndValue
- StringBuffer sb = new StringBuffer();
-
- boolean isFirst = true;
-
- for ( AttributeTypeAndValue ata:atavs )
- {
- if ( isFirst )
- {
- isFirst = false;
- }
- else
- {
- sb.append( '+' );
- }
-
- sb.append( ata.normalize() );
- }
-
- normName = sb.toString();
- break;
- }
- }
-
-
- /**
- * Add a AttributeTypeAndValue to the current RDN
- *
- * @param upType The user provided type of the added RDN.
- * @param type The normalized provided type of the added RDN.
- * @param upValue The user provided value of the added RDN
- * @param value The normalized provided value of the added RDN
- * @throws InvalidNameException
- * If the RDN is invalid
- */
- // WARNING : The protection level is left unspecified intentionally.
- // We need this method to be visible from the DnParser class, but not
- // from outside this package.
- @SuppressWarnings({"unchecked"})
- /* Unspecified protection */void addAttributeTypeAndValue( String upType, String type, Value<?> upValue, Value<?> value )
- throws InvalidNameException
- {
- // First, let's normalize the type
- String normalizedType = StringTools.lowerCaseAscii(type);
- Value<?> normalizedValue = value;
-
- switch ( nbAtavs )
- {
- case 0:
- // This is the first AttributeTypeAndValue. Just stores it.
- atav = new AttributeTypeAndValue( upType, type, upValue, normalizedValue );
- nbAtavs = 1;
- atavType = normalizedType;
- 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<AttributeTypeAndValue>();
-
- // and store the existing AttributeTypeAndValue into it.
- atavs.add( atav );
- atavTypes = new MultiValueMap();
- atavTypes.put( atavType, atav );
-
- atav = null;
-
- // Now, fall down to the commmon case
- // NO BREAK !!!
-
- default:
- // add a new AttributeTypeAndValue
- AttributeTypeAndValue newAtav = new AttributeTypeAndValue( upType, type, upValue, normalizedValue );
- atavs.add( newAtav );
- atavTypes.put( normalizedType, newAtav );
-
- nbAtavs++;
- break;
-
- }
- }
-
-
- /**
- * Add a AttributeTypeAndValue to the current RDN
- *
- * @param value The added AttributeTypeAndValue
- */
- // 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.
- @SuppressWarnings({"unchecked"})
- /* Unspecified protection */void addAttributeTypeAndValue( AttributeTypeAndValue value )
- {
- String normalizedType = value.getNormType();
-
- switch ( nbAtavs )
- {
- case 0:
- // This is the first AttributeTypeAndValue. Just stores it.
- this.atav = value;
- nbAtavs = 1;
- atavType = normalizedType;
- 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<AttributeTypeAndValue>();
-
- // and store the existing AttributeTypeAndValue into it.
- atavs.add( this.atav );
- atavTypes = new MultiValueMap();
- atavTypes.put( atavType, this.atav );
-
- this.atav = null;
-
- // Now, fall down to the commmon case
- // NO BREAK !!!
-
- default:
- // add a new AttributeTypeAndValue
- atavs.add( value );
- atavTypes.put( normalizedType, value );
-
- nbAtavs++;
- break;
-
- }
- }
-
-
- /**
- * Clear the RDN, removing all the AttributeTypeAndValues.
- */
- public void clear()
- {
- atav = null;
- atavs = null;
- atavType = null;
- atavTypes.clear();
- nbAtavs = 0;
- normName = "";
- upName = "";
- start = -1;
- length = 0;
- }
-
-
- /**
- * 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.
- * @throws InvalidNameException
- */
- public Object getValue( String type ) throws InvalidNameException
- {
- // First, let's normalize the type
- String normalizedType = StringTools.lowerCaseAscii( StringTools.trim( type ) );
-
- switch ( nbAtavs )
- {
- case 0:
- return "";
-
- case 1:
- if ( StringTools.equals( atav.getNormType(), normalizedType ) )
- {
- return atav.getNormValue().get();
- }
-
- return "";
-
- default:
- if ( atavTypes.containsKey( normalizedType ) )
- {
- Object obj = atavTypes.get( normalizedType );
-
- if ( obj instanceof AttributeTypeAndValue )
- {
- return ( ( AttributeTypeAndValue ) obj ).getNormValue();
- }
- else if ( obj instanceof List )
- {
- StringBuffer sb = new StringBuffer();
- boolean isFirst = true;
- List<AttributeTypeAndValue> atavList = ( ( List<AttributeTypeAndValue> ) obj );
-
- for ( AttributeTypeAndValue elem:atavList )
- {
- if ( isFirst )
- {
- isFirst = false;
- }
- else
- {
- sb.append( ',' );
- }
-
- sb.append( elem.getNormValue() );
- }
-
- return sb.toString();
- }
- else
- {
- throw new InvalidNameException( "Bad object stored in the RDN" );
- }
- }
-
- return "";
- }
- }
-
-
- /**
- * Get the start position
- *
- * @return The start position in the DN
- */
- public int getStart()
- {
- return start;
- }
-
-
- /**
- * Get the Rdn length
- *
- * @return The Rdn length
- */
- public int getLength()
- {
- return length;
- }
-
- /**
- * 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.lowerCaseAscii( StringTools.trim( type ) );
-
- switch ( nbAtavs )
- {
- case 0:
- return null;
-
- case 1:
- if ( atav.getNormType().equals( normalizedType ) )
- {
- return atav;
- }
-
- return null;
-
- default:
- if ( atavTypes.containsKey( normalizedType ) )
- {
- return atavTypes.get( normalizedType );
- }
-
- return null;
- }
- }
-
-
- /**
- * Retrieves the components of this RDN as an iterator of AttributeTypeAndValue.
- * The effect on the iterator of updates to this RDN is undefined. If the
- * RDN has zero components, an empty (non-null) iterator is returned.
- *
- * @return an iterator of the components of this RDN, each an AttributeTypeAndValue
- */
- public Iterator<AttributeTypeAndValue> iterator()
- {
- if ( nbAtavs == 1 || nbAtavs == 0 )
- {
- return new Iterator<AttributeTypeAndValue>()
- {
- private boolean hasMoreElement = nbAtavs == 1;
-
-
- public boolean hasNext()
- {
- return hasMoreElement;
- }
-
-
- public AttributeTypeAndValue next()
- {
- AttributeTypeAndValue obj = atav;
- hasMoreElement = false;
- return obj;
- }
-
-
- public void remove()
- {
- // nothing to do
- }
- };
- }
- else
- {
- return atavs.iterator();
- }
- }
-
-
- /**
- * Clone the Rdn
- *
- * @return A clone of the current 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 = atavTypes;
- break;
-
- default:
- // We must duplicate the treeSet and the hashMap
- rdn.atavTypes = new MultiValueMap();
- rdn.atavs = new TreeSet<AttributeTypeAndValue>();
-
- for ( AttributeTypeAndValue currentAtav:this.atavs )
- {
- rdn.atavs.add( (AttributeTypeAndValue)currentAtav.clone() );
- rdn.atavTypes.put( currentAtav.getNormType(), currentAtav );
- }
-
- break;
- }
-
- return rdn;
- }
- catch ( CloneNotSupportedException cnse )
- {
- throw new Error( "Assertion failure" );
- }
- }
-
-
- /**
- * Compares two RDNs. They are equals if :
- * <li>their have the same number of NC (AttributeTypeAndValue)
- * <li>each ATAVs are equals
- * <li>comparison of type are done case insensitive
- * <li>each value is equal, case sensitive
- * <li>Order of ATAV is not important If the RDNs are not equals, a positive number is
- * returned if the first RDN is greater, negative otherwise
- *
- * @param object
- * @return 0 if both rdn are equals. -1 if the current RDN is inferior, 1 if
- * the current Rdn is superior, UNDEFINED otherwise.
- */
- public int compareTo( Object object )
- {
- if ( object == null )
- {
- return SUPERIOR;
- }
-
- if ( object instanceof Rdn )
- {
- Rdn rdn = ( Rdn ) object;
-
- 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 EQUAL;
-
- case 1:
- return atav.compareTo( rdn.atav );
-
- default:
- // We have more than one value. We will
- // go through all of them.
-
- // the types are already normalized and sorted in the atavs TreeSet
- // so we could compare the 1st with the 1st, then the 2nd with the 2nd, etc.
- Iterator<AttributeTypeAndValue> localIterator = atavs.iterator();
- Iterator<AttributeTypeAndValue> paramIterator = rdn.atavs.iterator();
-
- while(localIterator.hasNext() || paramIterator.hasNext())
- {
- if(!localIterator.hasNext())
- {
- return SUPERIOR;
- }
- if(!paramIterator.hasNext())
- {
- return INFERIOR;
- }
-
- AttributeTypeAndValue localAtav = localIterator.next();
- AttributeTypeAndValue paramAtav = paramIterator.next();
- int result = localAtav.compareTo( paramAtav );
- if ( result != EQUAL )
- {
- return result;
- }
- }
-
- return EQUAL;
- }
- }
- else
- {
- return UNDEFINED;
- }
- }
+ /**
+ * 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 = "";
+ normName = "";
+ }
- /**
- * @return a String representation of the RDN
- */
- public String toString()
- {
- return normName == null ? "" : normName;
- }
+ /**
+ * A constructor that parse a String representing a RDN.
+ *
+ * @param rdn The String containing the RDN to parse
+ * @throws InvalidNameException If the RDN is invalid
+ */
+ public Rdn( String rdn ) throws InvalidNameException
+ {
+ start = 0;
+ if ( StringTools.isNotEmpty( rdn ) )
+ {
+ // Parse the string. The Rdn will be updated.
+ RdnParser.parse( rdn, this );
- /**
- * @return the user provided name
- */
- public String getUpName()
- {
- return upName;
- }
+ // create the internal normalized form
+ // and store the user provided form
+ normalize();
+ upName = rdn;
+ length = rdn.length();
+ }
+ else
+ {
+ upName = "";
+ normName = "";
+ length = 0;
+ }
+ }
- /**
- * @return The normalized name
- */
- public String getNormName()
- {
- return normName == null ? "" : normName;
- }
+ /**
+ * 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 interpreted as RFC 2253 formatted RDN strings. That is,
+ * the values are used literally (not parsed) and assumed to be un-escaped.
+ *
+ * @param upType The user provided type of the RDN
+ * @param upValue The user provided value of the RDN
+ * @param normType The normalized provided type of the RDN
+ * @param normValue The normalized provided value of the RDN
+ * @throws InvalidNameException If the RDN is invalid
+ */
+ public Rdn( String upType, String normType, String upValue, String normValue ) throws InvalidNameException
+ {
+ addAttributeTypeAndValue( upType, normType, new ClientStringValue( upValue ), new ClientStringValue( normValue ) );
+ upName = upType + '=' + upValue;
+ start = 0;
+ length = upName.length();
+ // create the internal normalized form
+ normalize();
+ }
- /**
- * Set the User Provided Name
- * @param upName the User Provided dame
- */
- public void setUpName( String upName )
- {
- this.upName = upName;
- }
+ /**
+ * A constructor that constructs a RDN from a type, a position and a length.
+ *
+ * @param start The starting point for this RDN in the user provided DN
+ * @param length The RDN's length
+ * @param upName The user provided name
+ * @param normName the normalized name
+ */
+ /* No protection */Rdn( int start, int length, String upName, String normName )
+ {
+ this.start = 0;
+ this.length = length;
+ this.upName = upName;
+ this.normName = normName;
+ }
- /**
- * @return Returns the nbAtavs.
- */
- public int getNbAtavs()
- {
- return nbAtavs;
- }
+ /**
+ * 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.
+ */
+ @SuppressWarnings(
+ { "unchecked" })
+ public Rdn( Rdn rdn )
+ {
+ nbAtavs = rdn.getNbAtavs();
+ this.normName = rdn.normName;
+ this.upName = rdn.getUpName();
+ this.start = rdn.start;
+ this.length = rdn.length;
+
+ switch ( rdn.getNbAtavs() )
+ {
+ case 0:
+ return;
+
+ case 1:
+ this.atav = ( AttributeTypeAndValue ) rdn.atav.clone();
+ return;
+
+ default:
+ // We must duplicate the treeSet and the hashMap
+ atavs = new TreeSet<AttributeTypeAndValue>();
+ atavTypes = new MultiValueMap();
+
+ for ( AttributeTypeAndValue currentAtav : rdn.atavs )
+ {
+ atavs.add( ( AttributeTypeAndValue ) currentAtav.clone() );
+ atavTypes.put( currentAtav.getNormType(), currentAtav );
+ }
+
+ return;
+ }
+ }
+
+
+ /**
+ * 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 normalize()
+ {
+ switch ( nbAtavs )
+ {
+ case 0:
+ // An empty RDN
+ normName = "";
+ break;
+
+ case 1:
+ // We have a single AttributeTypeAndValue
+ // We will trim and lowercase type and value.
+ if ( !atav.getNormValue().isBinary() )
+ {
+ normName = atav.getNormalizedValue();
+ }
+ else
+ {
+ normName = atav.getNormType() + "=#" + StringTools.dumpHexPairs( atav.getNormValue().getBytes() );
+ }
+
+ break;
+
+ default:
+ // We have more than one AttributeTypeAndValue
+ StringBuffer sb = new StringBuffer();
+
+ boolean isFirst = true;
+
+ for ( AttributeTypeAndValue ata : atavs )
+ {
+ if ( isFirst )
+ {
+ isFirst = false;
+ }
+ else
+ {
+ sb.append( '+' );
+ }
+
+ sb.append( ata.normalize() );
+ }
+
+ normName = sb.toString();
+ break;
+ }
+ }
+
+
+ /**
+ * Add a AttributeTypeAndValue to the current RDN
+ *
+ * @param upType The user provided type of the added RDN.
+ * @param type The normalized provided type of the added RDN.
+ * @param upValue The user provided value of the added RDN
+ * @param value The normalized provided value of the added RDN
+ * @throws InvalidNameException
+ * If the RDN is invalid
+ */
+ // WARNING : The protection level is left unspecified intentionally.
+ // We need this method to be visible from the DnParser class, but not
+ // from outside this package.
+ @SuppressWarnings(
+ { "unchecked" })
+ /* Unspecified protection */void addAttributeTypeAndValue( String upType, String type, Value<?> upValue,
+ Value<?> value ) throws InvalidNameException
+ {
+ // First, let's normalize the type
+ String normalizedType = StringTools.lowerCaseAscii( type );
+ Value<?> normalizedValue = value;
+
+ switch ( nbAtavs )
+ {
+ case 0:
+ // This is the first AttributeTypeAndValue. Just stores it.
+ atav = new AttributeTypeAndValue( upType, type, upValue, normalizedValue );
+ nbAtavs = 1;
+ atavType = normalizedType;
+ 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<AttributeTypeAndValue>();
+
+ // and store the existing AttributeTypeAndValue into it.
+ atavs.add( atav );
+ atavTypes = new MultiValueMap();
+ atavTypes.put( atavType, atav );
+
+ atav = null;
+
+ // Now, fall down to the commmon case
+ // NO BREAK !!!
+
+ default:
+ // add a new AttributeTypeAndValue
+ AttributeTypeAndValue newAtav = new AttributeTypeAndValue( upType, type, upValue, normalizedValue );
+ atavs.add( newAtav );
+ atavTypes.put( normalizedType, newAtav );
+
+ nbAtavs++;
+ break;
+
+ }
+ }
+
+
+ /**
+ * Add a AttributeTypeAndValue to the current RDN
+ *
+ * @param value The added AttributeTypeAndValue
+ */
+ // 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.
+ @SuppressWarnings(
+ { "unchecked" })
+ /* Unspecified protection */void addAttributeTypeAndValue( AttributeTypeAndValue value )
+ {
+ String normalizedType = value.getNormType();
+
+ switch ( nbAtavs )
+ {
+ case 0:
+ // This is the first AttributeTypeAndValue. Just stores it.
+ this.atav = value;
+ nbAtavs = 1;
+ atavType = normalizedType;
+ 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<AttributeTypeAndValue>();
+
+ // and store the existing AttributeTypeAndValue into it.
+ atavs.add( this.atav );
+ atavTypes = new MultiValueMap();
+ atavTypes.put( atavType, this.atav );
+
+ this.atav = null;
+
+ // Now, fall down to the commmon case
+ // NO BREAK !!!
+
+ default:
+ // add a new AttributeTypeAndValue
+ atavs.add( value );
+ atavTypes.put( normalizedType, value );
+
+ nbAtavs++;
+ break;
+
+ }
+ }
+
+
+ /**
+ * Clear the RDN, removing all the AttributeTypeAndValues.
+ */
+ public void clear()
+ {
+ atav = null;
+ atavs = null;
+ atavType = null;
+ atavTypes.clear();
+ nbAtavs = 0;
+ normName = "";
+ upName = "";
+ start = -1;
+ length = 0;
+ }
+
+
+ /**
+ * 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.
+ * @throws InvalidNameException
+ */
+ public Object getValue( String type ) throws InvalidNameException
+ {
+ // First, let's normalize the type
+ String normalizedType = StringTools.lowerCaseAscii( StringTools.trim( type ) );
+
+ switch ( nbAtavs )
+ {
+ case 0:
+ return "";
+
+ case 1:
+ if ( StringTools.equals( atav.getNormType(), normalizedType ) )
+ {
+ return atav.getNormValue().get();
+ }
+
+ return "";
+
+ default:
+ if ( atavTypes.containsKey( normalizedType ) )
+ {
+ Object obj = atavTypes.get( normalizedType );
+
+ if ( obj instanceof AttributeTypeAndValue )
+ {
+ return ( ( AttributeTypeAndValue ) obj ).getNormValue();
+ }
+ else if ( obj instanceof List )
+ {
+ StringBuffer sb = new StringBuffer();
+ boolean isFirst = true;
+ List<AttributeTypeAndValue> atavList = ( ( List<AttributeTypeAndValue> ) obj );
+
+ for ( AttributeTypeAndValue elem : atavList )
+ {
+ if ( isFirst )
+ {
+ isFirst = false;
+ }
+ else
+ {
+ sb.append( ',' );
+ }
+
+ sb.append( elem.getNormValue() );
+ }
+
+ return sb.toString();
+ }
+ else
+ {
+ throw new InvalidNameException( "Bad object stored in the RDN" );
+ }
+ }
+
+ return "";
+ }
+ }
+
+
+ /**
+ * Get the start position
+ *
+ * @return The start position in the DN
+ */
+ public int getStart()
+ {
+ return start;
+ }
+
+
+ /**
+ * Get the Rdn length
+ *
+ * @return The Rdn length
+ */
+ public int getLength()
+ {
+ return length;
+ }
+
+
+ /**
+ * 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.lowerCaseAscii( StringTools.trim( type ) );
+
+ switch ( nbAtavs )
+ {
+ case 0:
+ return null;
+
+ case 1:
+ if ( atav.getNormType().equals( normalizedType ) )
+ {
+ return atav;
+ }
+
+ return null;
+
+ default:
+ if ( atavTypes.containsKey( normalizedType ) )
+ {
+ return atavTypes.get( normalizedType );
+ }
+
+ return null;
+ }
+ }
+
+
+ /**
+ * Retrieves the components of this RDN as an iterator of AttributeTypeAndValue.
+ * The effect on the iterator of updates to this RDN is undefined. If the
+ * RDN has zero components, an empty (non-null) iterator is returned.
+ *
+ * @return an iterator of the components of this RDN, each an AttributeTypeAndValue
+ */
+ public Iterator<AttributeTypeAndValue> iterator()
+ {
+ if ( nbAtavs == 1 || nbAtavs == 0 )
+ {
+ return new Iterator<AttributeTypeAndValue>()
+ {
+ private boolean hasMoreElement = nbAtavs == 1;
+
+
+ public boolean hasNext()
+ {
+ return hasMoreElement;
+ }
+
+
+ public AttributeTypeAndValue next()
+ {
+ AttributeTypeAndValue obj = atav;
+ hasMoreElement = false;
+ return obj;
+ }
+
+
+ public void remove()
+ {
+ // nothing to do
+ }
+ };
+ }
+ else
+ {
+ return atavs.iterator();
+ }
+ }
+
+
+ /**
+ * Clone the Rdn
+ *
+ * @return A clone of the current 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 = atavTypes;
+ break;
+
+ default:
+ // We must duplicate the treeSet and the hashMap
+ rdn.atavTypes = new MultiValueMap();
+ rdn.atavs = new TreeSet<AttributeTypeAndValue>();
+
+ for ( AttributeTypeAndValue currentAtav : this.atavs )
+ {
+ rdn.atavs.add( ( AttributeTypeAndValue ) currentAtav.clone() );
+ rdn.atavTypes.put( currentAtav.getNormType(), currentAtav );
+ }
+
+ break;
+ }
+
+ return rdn;
+ }
+ catch ( CloneNotSupportedException cnse )
+ {
+ throw new Error( "Assertion failure" );
+ }
+ }
+
+
+ /**
+ * Compares two RDNs. They are equals if :
+ * <li>their have the same number of NC (AttributeTypeAndValue)
+ * <li>each ATAVs are equals
+ * <li>comparison of type are done case insensitive
+ * <li>each value is equal, case sensitive
+ * <li>Order of ATAV is not important If the RDNs are not equals, a positive number is
+ * returned if the first RDN is greater, negative otherwise
+ *
+ * @param object
+ * @return 0 if both rdn are equals. -1 if the current RDN is inferior, 1 if
+ * the current Rdn is superior, UNDEFINED otherwise.
+ */
+ public int compareTo( Object object )
+ {
+ if ( object == null )
+ {
+ return SUPERIOR;
+ }
+
+ if ( object instanceof Rdn )
+ {
+ Rdn rdn = ( Rdn ) object;
+
+ 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 EQUAL;
+
+ case 1:
+ return atav.compareTo( rdn.atav );
+
+ default:
+ // We have more than one value. We will
+ // go through all of them.
+
+ // the types are already normalized and sorted in the atavs TreeSet
+ // so we could compare the 1st with the 1st, then the 2nd with the 2nd, etc.
+ Iterator<AttributeTypeAndValue> localIterator = atavs.iterator();
+ Iterator<AttributeTypeAndValue> paramIterator = rdn.atavs.iterator();
+
+ while ( localIterator.hasNext() || paramIterator.hasNext() )
+ {
+ if ( !localIterator.hasNext() )
+ {
+ return SUPERIOR;
+ }
+ if ( !paramIterator.hasNext() )
+ {
+ return INFERIOR;
+ }
+
+ AttributeTypeAndValue localAtav = localIterator.next();
+ AttributeTypeAndValue paramAtav = paramIterator.next();
+ int result = localAtav.compareTo( paramAtav );
+ if ( result != EQUAL )
+ {
+ return result;
+ }
+ }
+
+ return EQUAL;
+ }
+ }
+ else
+ {
+ return UNDEFINED;
+ }
+ }
+
+
+ /**
+ * @return a String representation of the RDN
+ */
+ public String toString()
+ {
+ return normName == null ? "" : normName;
+ }
+
+
+ /**
+ * @return the user provided name
+ */
+ public String getUpName()
+ {
+ return upName;
+ }
+
+
+ /**
+ * @return The normalized name
+ */
+ public String getNormName()
+ {
+ return normName == null ? "" : normName;
+ }
+
+
+ /**
+ * Set the User Provided Name
+ * @param upName the User Provided dame
+ */
+ 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 ( ( TreeSet<AttributeTypeAndValue> ) atavs ).first();
+ }
+ }
+
+
+ /**
+ * Return the user provided type, or the first one of we have more than one (the lowest)
+ *
+ * @return The first user provided type of this RDN
+ */
+ public String getUpType()
+ {
+ switch ( nbAtavs )
+ {
+ case 0:
+ return null;
+
+ case 1:
+ return atav.getUpType();
+
+ default:
+ return ( ( TreeSet<AttributeTypeAndValue> ) atavs ).first().getUpType();
+ }
+ }
+
+
+ /**
+ * Return the normalized type, or the first one of we have more than one (the lowest)
+ *
+ * @return The first normalized type of this RDN
+ */
+ public String getNormType()
+ {
+ switch ( nbAtavs )
+ {
+ case 0:
+ return null;
+
+ case 1:
+ return atav.getNormType();
+
+ default:
+ return ( ( TreeSet<AttributeTypeAndValue> ) atavs ).first().getNormType();
+ }
+ }
+
+
+ /**
+ * Return the value, or the first one of we have more than one (the lowest)
+ *
+ * @return The first value of this RDN
+ */
+ public Object getValue()
+ {
+ switch ( nbAtavs )
+ {
+ case 0:
+ return null;
+
+ case 1:
+ return atav.getNormValue().get();
+
+ default:
+ return ( ( TreeSet<AttributeTypeAndValue> ) atavs ).first().getNormValue().get();
+ }
+ }
+
+
+ /**
+ * Return the User Provided value
+ *
+ * @return The first User provided value of this RDN
+ */
+ public String getUpValue()
+ {
+ switch ( nbAtavs )
+ {
+ case 0:
+ return null;
+
+ case 1:
+ return atav.getUpValue().getString();
+
+ default:
+ return ( ( TreeSet<AttributeTypeAndValue> ) atavs ).first().getUpValue().getString();
+ }
+ }
- /**
- * 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 ((TreeSet<AttributeTypeAndValue>)atavs).first();
- }
- }
-
-
- /**
- * Return the user provided type, or the first one of we have more than one (the lowest)
- *
- * @return The first user provided type of this RDN
- */
- public String getUpType()
- {
- switch ( nbAtavs )
- {
- case 0:
- return null;
-
- case 1:
- return atav.getUpType();
-
- default:
- return ((TreeSet<AttributeTypeAndValue>)atavs).first().getUpType();
- }
- }
-
- /**
- * Return the normalized type, or the first one of we have more than one (the lowest)
- *
- * @return The first normalized type of this RDN
- */
- public String getNormType()
- {
- switch ( nbAtavs )
- {
- case 0:
- return null;
-
- case 1:
- return atav.getNormType();
-
- default:
- return ((TreeSet<AttributeTypeAndValue>)atavs).first().getNormType();
- }
- }
-
- /**
- * Return the value, or the first one of we have more than one (the lowest)
- *
- * @return The first value of this RDN
- */
- public Object getValue()
- {
- switch ( nbAtavs )
- {
- case 0:
- return null;
-
- case 1:
- return atav.getNormValue().get();
-
- default:
- return ((TreeSet<AttributeTypeAndValue>)atavs).first().getNormValue().get();
- }
- }
-
-
- /**
- * Return the User Provided value
- *
- * @return The first User provided value of this RDN
- */
- public String getUpValue()
- {
- switch ( nbAtavs )
- {
- case 0:
- return null;
-
- case 1:
- return atav.getUpValue().getString();
-
- default:
- return ((TreeSet<AttributeTypeAndValue>)atavs).first().getUpValue().getString();
- }
- }
-
/**
* Return the normalized value, or the first one of we have more than one (the lowest)
*
@@ -947,509 +952,511 @@
{
case 0:
return null;
-
+
case 1:
return atav.getNormValue().getString();
-
+
default:
- return ((TreeSet<AttributeTypeAndValue>)atavs).first().getNormalizedValue();
+ return ( ( TreeSet<AttributeTypeAndValue> ) atavs ).first().getNormalizedValue();
+ }
+ }
+
+
+ /**
+ * 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 ) == EQUAL;
+ }
+
+
+ /**
+ * Get the number of Attribute type and value of this Rdn
+ *
+ * @return The number of ATAVs in this Rdn
+ */
+ public int size()
+ {
+ return nbAtavs;
+ }
+
+
+ /**
+ * 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 )
+ {
+ 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++] = StringTools.getHexValue( chars[i], 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.getHexValue( chars[i] ) << 4 ) );
+ }
+
+ break;
+ }
+ }
+ else
+ {
+ if ( isHex )
+ {
+ if ( StringTools.isHex( chars, i ) )
+ {
+ pair += StringTools.getHexValue( 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 '#':
+ if ( i != 0 )
+ {
+ // '#' are allowed if not in first position
+ bytes[pos++] = '#';
+ break;
+ }
+ case '=':
+ throw new IllegalArgumentException( "Unescaped special characters are not allowed" );
+
+ case ' ':
+ if ( ( i == 0 ) || ( i == chars.length - 1 ) )
+ {
+ throw new IllegalArgumentException( "Unescaped special characters are not allowed" );
+ }
+ else
+ {
+ bytes[pos++] = ' ';
+ break;
+ }
+
+ default:
+ if ( ( chars[i] >= 0 ) && ( chars[i] < 128 ) )
+ {
+ bytes[pos++] = ( byte ) chars[i];
+ }
+ else
+ {
+ byte[] result = StringTools.charToBytes( chars[i] );
+ System.arraycopy( result, 0, bytes, pos, result.length );
+ pos += result.length;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ return StringTools.utf8ToString( bytes, pos );
+ }
+ }
+
+
+ /**
+ * Transform a value in a String, accordingly to RFC 2253
+ *
+ * @param value The attribute value to be escaped
+ * @return The escaped string value.
+ */
+ public static String escapeValue( String value )
+ {
+ if ( StringTools.isEmpty( value ) )
+ {
+ return "";
+ }
+
+ 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 ' ':
+ if ( ( i > 0 ) && ( i < chars.length - 1 ) )
+ {
+ newChars[pos++] = chars[i];
+ }
+ else
+ {
+ newChars[pos++] = '\\';
+ newChars[pos++] = chars[i];
+ }
+
+ break;
+
+ case '#':
+ if ( i != 0 )
+ {
+ newChars[pos++] = chars[i];
+ }
+ else
+ {
+ newChars[pos++] = '\\';
+ newChars[pos++] = chars[i];
+ }
+
+ break;
+
+ 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];
+ break;
+
+ }
+ }
+
+ return new String( newChars, 0, 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( byte[] attrValue )
+ {
+ if ( StringTools.isEmpty( attrValue ) )
+ {
+ return "";
+ }
+
+ String value = StringTools.utf8ToString( attrValue );
+
+ return escapeValue( value );
+ }
+
+
+ /**
+ * Gets the hashcode of this rdn.
+ *
+ * @see java.lang.Object#hashCode()
+ * @return the instance's hash code
+ */
+ public int hashCode()
+ {
+ int result = 37;
+
+ switch ( nbAtavs )
+ {
+ case 0:
+ // An empty RDN
+ break;
+
+ case 1:
+ // We have a single AttributeTypeAndValue
+ result = result * 17 + atav.hashCode();
+ break;
+
+ default:
+ // We have more than one AttributeTypeAndValue
+
+ for ( AttributeTypeAndValue ata : atavs )
+ {
+ result = result * 17 + ata.hashCode();
+ }
+
+ break;
+ }
+
+ return result;
+ }
+
+
+ /**
+ * @see Externalizable#readExternal(ObjectInput)<p>
+ *
+ * A RDN is composed of on to many ATAVs (AttributeType And Value).
+ * We should write all those ATAVs sequencially, following the
+ * structure :
+ *
+ * <li>nbAtavs</li> The number of ATAVs to write. Can't be 0.
+ * <li>upName</li> The User provided RDN
+ * <li>normName</li> The normalized RDN. It can be empty if the normalized
+ * name equals the upName.
+ * <li>atavs</li>
+ * <p>
+ * For each ATAV :<p>
+ * <li>start</li> The position of this ATAV in the upName string
+ * <li>length</li> The ATAV user provided length
+ * <li>Call the ATAV write method</li> The ATAV itself
+ *
+ * @param out The stream into which the serialized RDN will be put
+ * @throws IOException If the stream can't be written
+ */
+ public void writeExternal( ObjectOutput out ) throws IOException
+ {
+ out.writeInt( nbAtavs );
+ out.writeUTF( upName );
+
+ if ( upName.equals( normName ) )
+ {
+ out.writeUTF( "" );
+ }
+ else
+ {
+ out.writeUTF( normName );
+ }
+
+ out.writeInt( start );
+ out.writeInt( length );
+
+ switch ( nbAtavs )
+ {
+ case 0:
+ break;
+
+ case 1:
+ out.writeObject( atav );
+ break;
+
+ default:
+ for ( AttributeTypeAndValue value : atavs )
+ {
+ out.writeObject( value );
+ }
+
+ break;
+ }
+ }
+
+
+ /**
+ * @see Externalizable#readExternal(ObjectInput)
+ *
+ * We read back the data to create a new RDB. The structure
+ * read is exposed in the {@link Rdn#writeExternal(ObjectOutput)}
+ * method<p>
+ *
+ * @param in The input stream from which the RDN will be read
+ * @throws IOException If we can't read from the input stream
+ * @throws ClassNotFoundException If we can't create a new RDN
+ */
+ public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
+ {
+ // Read the ATAV number
+ nbAtavs = in.readInt();
+
+ // Read the UPName
+ upName = in.readUTF();
+
+ // Read the normName
+ normName = in.readUTF();
+
+ if ( StringTools.isEmpty( normName ) )
+ {
+ normName = upName;
+ }
+
+ start = in.readInt();
+ length = in.readInt();
+
+ switch ( nbAtavs )
+ {
+ case 0:
+ atav = null;
+ break;
+
+ case 1:
+ atav = ( AttributeTypeAndValue ) in.readObject();
+ atavType = atav.getNormType();
+
+ break;
+
+ default:
+ atavs = new TreeSet<AttributeTypeAndValue>();
+
+ atavTypes = new MultiValueMap();
+
+ for ( int i = 0; i < nbAtavs; i++ )
+ {
+ AttributeTypeAndValue value = ( AttributeTypeAndValue ) in.readObject();
+ atavs.add( value );
+ atavTypes.put( value.getNormType(), value );
+ }
+
+ atav = null;
+ atavType = null;
+
+ break;
}
}
-
-
- /**
- * 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 ) == EQUAL;
- }
-
-
- /**
- * Get the number of Attribute type and value of this Rdn
- *
- * @return The number of ATAVs in this Rdn
- */
- public int size()
- {
- return nbAtavs;
- }
-
-
- /**
- * 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 )
- {
- 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++] = StringTools.getHexValue( chars[i], 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.getHexValue( chars[i] ) << 4 ) );
- }
-
- break;
- }
- }
- else
- {
- if ( isHex )
- {
- if ( StringTools.isHex( chars, i ) )
- {
- pair += StringTools.getHexValue( 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 '#':
- if ( i != 0)
- {
- // '#' are allowed if not in first position
- bytes[pos++] = '#';
- break;
- }
- case '=':
- throw new IllegalArgumentException( "Unescaped special characters are not allowed" );
-
- case ' ':
- if ( ( i == 0 ) || ( i == chars.length - 1) )
- {
- throw new IllegalArgumentException( "Unescaped special characters are not allowed" );
- }
- else
- {
- bytes[pos++] = ' ';
- break;
- }
-
- default:
- if ( ( chars[i] >= 0 ) && ( chars[i] < 128 ) )
- {
- bytes[pos++] = (byte)chars[i];
- }
- else
- {
- byte[] result = StringTools.charToBytes( chars[i] );
- System.arraycopy( result, 0, bytes, pos, result.length );
- pos += result.length;
- }
-
- break;
- }
- }
- }
- }
-
- return StringTools.utf8ToString( bytes, pos );
- }
- }
-
-
- /**
- * Transform a value in a String, accordingly to RFC 2253
- *
- * @param value The attribute value to be escaped
- * @return The escaped string value.
- */
- public static String escapeValue( String value )
- {
- if ( StringTools.isEmpty( value ) )
- {
- return "";
- }
-
- 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 ' ':
- if ( ( i > 0 ) && ( i < chars.length - 1 ) )
- {
- newChars[pos++] = chars[i];
- }
- else
- {
- newChars[pos++] = '\\';
- newChars[pos++] = chars[i];
- }
-
- break;
-
- case '#':
- if ( i != 0 )
- {
- newChars[pos++] = chars[i];
- }
- else
- {
- newChars[pos++] = '\\';
- newChars[pos++] = chars[i];
- }
-
- break;
-
- 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];
- break;
-
- }
- }
-
- return new String( newChars, 0, 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( byte[] attrValue )
- {
- if ( StringTools.isEmpty( attrValue ) )
- {
- return "";
- }
-
- String value = StringTools.utf8ToString( attrValue );
-
- return escapeValue( value );
- }
-
- /**
- * Gets the hashcode of this rdn.
- *
- * @see java.lang.Object#hashCode()
- * @return the instance's hash code
- */
- public int hashCode()
- {
- int result = 37;
-
- switch ( nbAtavs )
- {
- case 0:
- // An empty RDN
- break;
-
- case 1:
- // We have a single AttributeTypeAndValue
- result = result * 17 + atav.hashCode();
- break;
-
- default:
- // We have more than one AttributeTypeAndValue
-
- for ( AttributeTypeAndValue ata:atavs )
- {
- result = result * 17 + ata.hashCode();
- }
-
- break;
- }
-
- return result;
- }
-
-
- /**
- * @see Externalizable#readExternal(ObjectInput)<p>
- *
- * A RDN is composed of on to many ATAVs (AttributeType And Value).
- * We should write all those ATAVs sequencially, following the
- * structure :
- *
- * <li>nbAtavs</li> The number of ATAVs to write. Can't be 0.
- * <li>upName</li> The User provided RDN
- * <li>normName</li> The normalized RDN. It can be empty if the normalized
- * name equals the upName.
- * <li>atavs</li>
- * <p>
- * For each ATAV :<p>
- * <li>start</li> The position of this ATAV in the upName string
- * <li>length</li> The ATAV user provided length
- * <li>Call the ATAV write method</li> The ATAV itself
- *
- * @param out The stream into which the serialized RDN will be put
- * @throws IOException If the stream can't be written
- */
- public void writeExternal( ObjectOutput out ) throws IOException
- {
- out.writeInt( nbAtavs );
- out.writeUTF( upName );
-
- if ( upName.equals( normName ) )
- {
- out.writeUTF( "" );
- }
- else
- {
- out.writeUTF( normName );
- }
-
- out.writeInt( start );
- out.writeInt( length );
-
- switch ( nbAtavs )
- {
- case 0 :
- break;
-
- case 1 :
- out.writeObject( atav );
- break;
-
- default :
- for ( AttributeTypeAndValue value:atavs )
- {
- out.writeObject( value );
- }
-
- break;
- }
- }
-
-
- /**
- * @see Externalizable#readExternal(ObjectInput)
- *
- * We read back the data to create a new RDB. The structure
- * read is exposed in the {@link Rdn#writeExternal(ObjectOutput)}
- * method<p>
- *
- * @param in The input stream from which the RDN will be read
- * @throws IOException If we can't read from the input stream
- * @throws ClassNotFoundException If we can't create a new RDN
- */
- public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
- {
- // Read the ATAV number
- nbAtavs = in.readInt();
-
- // Read the UPName
- upName = in.readUTF();
-
- // Read the normName
- normName = in.readUTF();
-
- if ( StringTools.isEmpty( normName ) )
- {
- normName = upName;
- }
-
- start = in.readInt();
- length = in.readInt();
-
- switch ( nbAtavs )
- {
- case 0 :
- atav = null;
- break;
-
- case 1 :
- atav = (AttributeTypeAndValue)in.readObject();
- atavType = atav.getNormType();
-
- break;
-
- default :
- atavs = new TreeSet<AttributeTypeAndValue>();
-
- atavTypes = new MultiValueMap();
-
- for ( int i = 0; i < nbAtavs; i++ )
- {
- AttributeTypeAndValue value = (AttributeTypeAndValue)in.readObject();
- atavs.add( value );
- atavTypes.put( value.getNormType(), value );
- }
-
- atav = null;
- atavType = null;
-
- break;
- }
- }
}