You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2005/09/27 08:52:46 UTC
svn commit: r291833 - in
/directory/shared/ldap/branches/shared-ldap-NameComponent/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives:
LdapRDN.java NameComponent.java
Author: elecharny
Date: Mon Sep 26 23:52:40 2005
New Revision: 291833
URL: http://svn.apache.org/viewcvs?rev=291833&view=rev
Log:
Added the two classes
Added:
directory/shared/ldap/branches/shared-ldap-NameComponent/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapRDN.java
directory/shared/ldap/branches/shared-ldap-NameComponent/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/NameComponent.java
Added: directory/shared/ldap/branches/shared-ldap-NameComponent/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapRDN.java
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/branches/shared-ldap-NameComponent/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapRDN.java?rev=291833&view=auto
==============================================================================
--- directory/shared/ldap/branches/shared-ldap-NameComponent/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapRDN.java (added)
+++ directory/shared/ldap/branches/shared-ldap-NameComponent/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapRDN.java Mon Sep 26 23:52:40 2005
@@ -0,0 +1,1290 @@
+/*
+ * 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.asn1new.ldap.codec.primitives;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.naming.InvalidNameException;
+
+import org.apache.asn1new.ldap.codec.utils.DNUtils;
+import org.apache.asn1new.util.MutableString;
+import org.apache.asn1new.util.StringUtils;
+
+/**
+ * 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>
+ * 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>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ *
+ */
+public class LdapRDN implements Cloneable
+{
+ /**
+ * Stores all couple type = value. We may have more than one type,
+ * if the '+' character appears in the NameComponent. The key is
+ * the type, the value is a NameComponent.
+ */
+ private Map nameComponents;
+
+ /**
+ * A simple NameComponent is used to store the LdapRDN 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 NameComponent nameComponent;
+
+ private transient MutableString normalizedName;
+
+ /**
+ * A empty constructor.
+ */
+ public LdapRDN()
+ {
+ // Don't waste space... This is not so often we have multiple
+ // name-components in a RDN... So we won't initialize the Map.
+ nameComponents = null;
+ nameComponent = null;
+ normalizedName = null;
+ }
+
+ /**
+ * A constructor that parse a String RDN
+ *
+ * @param rdn The String containing the RDN to parse
+ * @throws InvalidNameException If the RDN is invalid
+ */
+ public LdapRDN( String rdn ) throws InvalidNameException
+ {
+ parseNameComponent( rdn, this );
+ }
+
+ /**
+ * A constructor that parse a RDN
+ *
+ * @param rdn The String containing the RDN to parse
+ * @throws InvalidNameException If the RDN is invalid
+ */
+
+ public LdapRDN( byte[] bytes ) throws InvalidNameException
+ {
+ parseNameComponent( bytes, 0, this );
+ }
+
+ /**
+ * A constructor that constructs a RDN from a type and a value
+ * @param type The type of the RDN
+ * @param value The value of the RDN
+ * @throws InvalidNameException If the RDN is invalid
+ */
+ public LdapRDN( String type, String value ) throws InvalidNameException
+ {
+ // Don't waste space... This is not so often we have multiple
+ // name-components in a RDN... So we won't initialize the Map.
+ nameComponents = null;
+ nameComponent = new NameComponent( type, value );
+ }
+
+ /**
+ * Add a NameComponent 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
+ */
+ public void addNameComponent( String type, String value) throws InvalidNameException
+ {
+ MutableString typeMs = null;
+
+ try
+ {
+ typeMs = new MutableString( type );
+ }
+ catch ( UnsupportedEncodingException uee )
+ {
+ throw new InvalidNameException( "Type '" + type + "' is not a valid UTF-8 string");
+ }
+
+ MutableString valueMs = null;
+
+ try
+ {
+ valueMs = new MutableString( value );
+ }
+ catch ( UnsupportedEncodingException uee )
+ {
+ throw new InvalidNameException( "Value '" + value + "' is not a valid UTF-8 string");
+ }
+
+ addNameComponent( typeMs, valueMs );
+ }
+
+ /**
+ * Add a NameComponent 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
+ */
+ public void addNameComponent( MutableString type, MutableString value) throws InvalidNameException
+ {
+ // First, check if we already have a NameComponent in this RDN
+ if ( ( nameComponent != null ) || ( nameComponents != null ) )
+ {
+ // Ok, we already have one NameComponent, at least.
+ // Do we have to create the HashMap ?
+ if ( nameComponents == null )
+ {
+ // First, create the HashMap if it's empty,
+ // and store the existing NameComponent into it.
+ nameComponents = new LinkedHashMap();
+
+ nameComponents.put( nameComponent.getType(), nameComponent );
+ }
+
+ nameComponent = new NameComponent( type, value );
+
+ // add a new NameComponent
+ nameComponents.put( nameComponent.getType(), nameComponent );
+ }
+ else
+ {
+ // This is the first NameComponent. Just stores it.
+ nameComponent = new NameComponent( type, value );
+ }
+ }
+
+ /**
+ * Remove a Name from a RDN
+ *
+ * @param type The nome to remove
+ * @throws InvalidNameException If the name does not exists or if the RDN is empty
+ */
+ public void removeNameComponent( String type ) throws InvalidNameException
+ {
+ if ( StringUtils.isEmpty( type ) )
+ {
+ return;
+ }
+
+ if ( nameComponents == null )
+ {
+ if ( nameComponent == null )
+ {
+ throw new InvalidNameException( "Cannot remove a nameComponent form an empty RDN" );
+ }
+ else if ( type.equals( nameComponent.getType() ) )
+ {
+ nameComponent = null;
+ }
+ else
+ {
+ throw new InvalidNameException( "Name '" + type + "' is not valid for the RDN '" + this.toString() + "'");
+ }
+ }
+ else
+ {
+ if ( nameComponents.containsKey( type ) )
+ {
+ nameComponents.remove( type );
+ }
+ else
+ {
+ throw new InvalidNameException( "Name '" + type + "' is not valid for the RDN '" + this.toString() + "'");
+ }
+ }
+ }
+
+ /**
+ * Clear the RDN, removing all the NameComponents.
+ */
+ public void clear()
+ {
+ nameComponent = null;
+ nameComponents = null;
+ }
+
+ public int getLength()
+ {
+ return
+ }
+
+ /**
+ * Get the Value of the NameComponent 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 MutableString getValue( String type ) throws InvalidNameException
+ {
+ MutableString typeMs = null;
+
+ try
+ {
+ typeMs = new MutableString( type );
+ }
+ catch ( UnsupportedEncodingException uee )
+ {
+ throw new InvalidNameException( "Type '" + type + "' is not a valid UTF-8 string");
+ }
+
+ // First, let's normalize the type
+ MutableString normalizedType = MutableString.trim( typeMs );
+ normalizedType.toLowerCase();
+
+ if ( nameComponents != null )
+ {
+ if ( nameComponents.containsKey( normalizedType ) )
+ {
+ return ( (NameComponent)nameComponents.get( normalizedType ) ).getValue();
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else
+ {
+ if ( MutableString.equals( nameComponent.getType(), normalizedType ) )
+ {
+ return nameComponent.getValue();
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Get the NameComponent which type is given as an argument.
+ *
+ * @param type The type of the NameArgument to be returned
+ * @return The NameComponent, of null if none is found.
+ */
+ public NameComponent getNameComponent( String type )
+ {
+ // First, let's normalize the type
+ String normalizedType = StringUtils.lowerCase( StringUtils.trim( type ) );
+
+ if ( nameComponents != null )
+ {
+ if ( nameComponents.containsKey( normalizedType ) )
+ {
+ return (NameComponent)nameComponents.get( normalizedType );
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else
+ {
+ if ( nameComponent.getType().equals( normalizedType ) )
+ {
+ return nameComponent;
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Parse this rule : <br>
+ * <p>
+ * <oidPrefix> ::= 'OID.' | 'oid.' | e
+ * </p>
+ *
+ * @param bytes The buffer to parse
+ * @param pos The current position in the char array
+ * @return The new position in the char array, or PARSING_ERROR if the rule does not apply to the char array
+ */
+ private static int parseOidPrefix( char[] chars, int pos )
+ {
+ if ( ( StringUtils.areEquals( chars, pos, DNUtils.OID_LOWER ) == DNUtils.PARSING_ERROR ) &&
+ ( StringUtils.areEquals( chars, pos, DNUtils.OID_UPPER ) == DNUtils.PARSING_ERROR ) )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ else
+ {
+ pos += DNUtils.OID_LOWER.length;
+
+ return pos;
+ }
+ }
+
+ /**
+ * Parse this rule : <br>
+ * <p>
+ * <oidPrefix> ::= 'OID.' | 'oid.' | e
+ * </p>
+ *
+ * @param bytes The buffer to parse
+ * @param pos The current position in the byte buffer
+ * @return The new position in the byte buffer, or -1 if the rule does not apply to the byte buffer
+ */
+ private static int parseOidPrefix( byte[] bytes, int pos )
+ {
+
+ if ( ( StringUtils.areEquals( bytes, pos, DNUtils.OID_LOWER_BYTES ) == DNUtils.PARSING_ERROR ) &&
+ ( StringUtils.areEquals( bytes, pos, DNUtils.OID_UPPER_BYTES ) == DNUtils.PARSING_ERROR ) )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ else
+ {
+ pos += DNUtils.OID_LOWER_BYTES.length;
+
+ return pos;
+ }
+ }
+
+ /**
+ * Parse this rule : <br>
+ * <p>
+ * <oidValue> ::= [0-9] <digits> <oids>
+ * </p>
+ *
+ * @param chars The char array to parse
+ * @param pos The current position in the byte buffer
+ * @return The new position in the char array, or PARSING_ERROR if the rule does not apply to the char array
+ */
+ private static int parseOidValue(char[] chars, int pos)
+ {
+ // <attributType> ::= [0-9] <digits> <oids>
+ if ( StringUtils.isDigit( chars, pos ) == false )
+ {
+ // Nope... An error
+ return DNUtils.PARSING_ERROR;
+ }
+ else
+ {
+ // Let's process an oid
+ pos++;
+
+ while ( StringUtils.isDigit( chars, pos ) )
+ {
+ pos++;
+ }
+
+ // <oids> ::= '.' [0-9] <digits> <oids> | e
+ if ( StringUtils.isCharASCII( chars, pos, '.' ) == false )
+ {
+ return pos;
+ }
+ else
+ {
+ do
+ {
+ pos++;
+
+ if ( StringUtils.isDigit( chars, pos ) == false )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ else
+ {
+ pos++;
+
+ while ( StringUtils.isDigit( chars, pos ) )
+ {
+ pos++;
+ }
+ }
+ }
+ while ( StringUtils.isCharASCII( chars, pos, '.' ) );
+
+ return pos;
+ }
+ }
+ }
+
+ /**
+ * Parse this rule : <br>
+ * <p>
+ * <oidValue> ::= [0-9] <digits> <oids>
+ * </p>
+ *
+ * @param bytes The buffer to parse
+ * @param pos The current position in the byte buffer
+ * @return The new position in the byte buffer, or -1 if the rule does not apply to the byte buffer
+ */
+ private static int parseOidValue(byte[] bytes, int pos)
+ {
+ // <attributType> ::= [0-9] <digits> <oids>
+ if ( StringUtils.isDigit( bytes, pos ) == false )
+ {
+
+ // Nope... An error
+ return DNUtils.PARSING_ERROR;
+ }
+ else
+ {
+
+ // Let's process an oid
+ pos++;
+
+ while ( StringUtils.isDigit( bytes, pos ) )
+ {
+ pos++;
+ }
+
+ // <oids> ::= '.' [0-9] <digits> <oids> | e
+ if ( StringUtils.isCharASCII( bytes, pos, '.' ) == false )
+ {
+
+ return pos;
+ }
+ else
+ {
+
+ do
+ {
+ pos++;
+
+ if ( StringUtils.isDigit( bytes, pos ) == false )
+ {
+
+ return DNUtils.PARSING_ERROR;
+ }
+ else
+ {
+ pos++;
+
+ while ( StringUtils.isDigit( bytes, pos ) )
+ {
+ pos++;
+ }
+ }
+ }
+ while ( StringUtils.isCharASCII( bytes, pos, '.' ) );
+
+ return pos;
+ }
+ }
+ }
+
+ /**
+ * Parse this rule : <br>
+ * <p>
+ * <attributType> ::= [a-zA-Z] <keychars> |
+ * <oidPrefix> [0-9] <digits> <oids> |
+ * [0-9] <digits> <oids>
+ * </p>
+ *
+ * The string *MUST* be an ASCII string, not an unicode string.
+ *
+ * @param chars The char array to parse
+ * @param pos The current position in the char array
+ * @return The new position in the char array, or PARSING_ERROR if the rule does not apply to the char array
+ */
+ private static int parseAttributeType( char[] chars, int pos )
+ {
+ // <attributType> ::= [a-zA-Z] <keychars> | <oidPrefix> [0-9] <digits> <oids> | [0-9] <digits> <oids>
+
+ if ( StringUtils.isAlphaASCII( chars, pos ))
+ {
+ // <attributType> ::= [a-zA-Z] <keychars> | <oidPrefix> [0-9] <digits> <oids>
+
+ // We have got an Alpha char, it may be the begining of an OID ?
+ int oldPos = pos;
+
+ if ( ( pos = parseOidPrefix( chars, oldPos ) ) != DNUtils.PARSING_ERROR )
+ {
+ return parseOidValue(chars, pos);
+ }
+ else
+ {
+ // It's not an oid, it's a String (ASCII)
+ // <attributType> ::= [a-zA-Z] <keychars>
+ // <keychars> ::= [a-zA-Z] <keychar> | [0-9] <keychar> | '-' <keychar> | e
+ pos = oldPos + 1;
+
+ while ( StringUtils.isAlphaDigitMinus( chars, pos ) )
+ {
+ pos++;
+ }
+
+ return pos;
+ }
+ }
+ else
+ {
+
+ // An oid
+ // <attributType> ::= [0-9] <digits> <oids>
+ return parseOidValue(chars, pos);
+ }
+ }
+
+ /**
+ * Parse this rule : <br>
+ * <p>
+ * <attributType> ::= [a-zA-Z] <keychars> |
+ * <oidPrefix> [0-9] <digits> <oids> | [0-9] <digits> <oids>
+ * </p>
+ *
+ * The string *MUST* be an ASCII string, not an unicode string.
+ *
+ * @param bytes The buffer to parse
+ * @param pos The current position in the byte buffer
+ * @return The new position in the byte buffer, or -1 if the rule does not apply to the byte buffer
+ */
+ private static int parseAttributeType( byte[] bytes, int pos )
+ {
+
+ // <attributType> ::= [a-zA-Z] <keychars> | <oidPrefix> [0-9] <digits> <oids> | [0-9] <digits> <oids>
+
+ if ( StringUtils.isAlphaASCII( bytes, pos ))
+ {
+ // <attributType> ::= [a-zA-Z] <keychars> | <oidPrefix> [0-9] <digits> <oids>
+
+ // We have got an Alpha char, it may be the begining of an OID ?
+ int oldPos = pos;
+
+ if ( ( pos = parseOidPrefix( bytes, oldPos ) ) != -1 )
+ {
+ return parseOidValue(bytes, pos);
+ }
+ else
+ {
+ // It's not an oid, it's a String (ASCII)
+ // <attributType> ::= [a-zA-Z] <keychars>
+ // <keychars> ::= [a-zA-Z] <keychar> | [0-9] <keychar> | '-' <keychar> | e
+ pos = oldPos + 1;
+
+ while ( StringUtils.isAlphaDigitMinus( bytes, pos ) )
+ {
+ pos++;
+ }
+
+ return pos;
+ }
+ }
+ else
+ {
+
+ // An oid
+ // <attributType> ::= [0-9] <digits> <oids>
+ return parseOidValue(bytes, pos);
+ }
+ }
+
+ /**
+ * Parse this rule : <br>
+ * <p>
+ * <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>
+ * </p>
+ *
+ * @param chars The char array to parse
+ * @param pos The current position in the char array
+ * @return The new position in the char array, or PARSING_ERROR if the rule does not apply to the char array
+ */
+ private static int parseAttributeValue( char[] chars, int pos )
+ {
+ if ( StringUtils.isCharASCII( chars, pos, '#' ) )
+ {
+ pos++;
+
+ // <attributeValue> ::= '#' <hexstring>
+ if ( ( pos = DNUtils.parseHexString( chars, pos ) ) == DNUtils.PARSING_ERROR )
+ {
+
+ return DNUtils.PARSING_ERROR;
+ }
+
+ return StringUtils.trimLeft( chars, pos );
+ }
+ else if ( StringUtils.isCharASCII( chars, pos, '"' ) )
+ {
+ pos++;
+ int nbBytes = 0;
+
+ // <attributeValue> ::= '"' <quotechar-or-pair> '"'
+ // <quotechar-or-pairs> ::= <quotechar> <quotechar-or-pairs> | '\' <pairchar> <quotechar-or-pairs> | e
+ while ( true )
+ {
+ if ( StringUtils.isCharASCII( chars, pos, '\\' ) )
+ {
+ pos++;
+
+ if ( DNUtils.isPairChar( chars, pos ) )
+ {
+ pos++;
+ }
+ else
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ }
+ else if ( (nbBytes = DNUtils.isQuoteChar( chars, pos ) ) != DNUtils.PARSING_ERROR )
+ {
+ pos += nbBytes;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if ( StringUtils.isCharASCII( chars, pos, '"' ) )
+ {
+ pos++;
+
+ return StringUtils.trimLeft( chars, pos );
+ }
+ else
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ }
+ else
+ {
+ while ( true )
+ {
+ if ( StringUtils.isCharASCII( chars, pos, '\\' ) )
+ {
+ // '\' <pairchar> <pairs-or-strings>
+ pos++;
+
+ if ( DNUtils.isPairChar( chars, pos ) == false )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ else
+ {
+ pos++;
+ }
+ }
+ else
+ {
+ int nbChars = 0;
+
+ // <stringchar> <pairs-or-strings>
+ if ( ( nbChars = DNUtils.isStringChar( chars, pos )) != DNUtils.PARSING_ERROR )
+ {
+ // A special case : if we have some spaces before the '+' character,
+ // we MUST skip them.
+ if ( StringUtils.isCharASCII( chars, pos, ' ') )
+ {
+ pos = StringUtils.trimLeft( chars, pos );
+
+ if ( ( DNUtils.isStringChar( chars, pos ) == DNUtils.PARSING_ERROR ) &&
+ ( StringUtils.isCharASCII( chars, pos, '\\' ) == false ) )
+ {
+ // Ok, we are done with the stringchar.
+ return pos;
+ }
+ }
+ else
+ {
+ // An unicode char could be more than one byte long
+ pos += nbChars;
+ }
+ }
+ else
+ {
+ return pos;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Parse this rule : <br>
+ * <p>
+ * <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>
+ * </p>
+ *
+ * @param bytes The buffer to parse
+ * @param pos The current position in the byte buffer
+ * @return The new position in the byte buffer, or -1 if the rule does not apply to the byte buffer
+ */
+ private static int parseAttributeValue( byte[] bytes, int pos )
+ {
+ if ( StringUtils.isCharASCII( bytes, pos, '#' ) )
+ {
+ pos++;
+
+ // <attributeValue> ::= '#' <hexstring>
+ if ( ( pos = DNUtils.parseHexString( bytes, pos ) ) == -1 )
+ {
+
+ return DNUtils.PARSING_ERROR;
+ }
+
+ return StringUtils.trimLeft( bytes, pos );
+ }
+ else if ( StringUtils.isCharASCII( bytes, pos, '"' ) )
+ {
+ pos++;
+ int nbBytes = 0;
+
+ // <attributeValue> ::= '"' <quotechar-or-pair> '"'
+ // <quotechar-or-pairs> ::= <quotechar> <quotechar-or-pairs> | '\' <pairchar> <quotechar-or-pairs> | e
+ while ( true )
+ {
+ if ( StringUtils.isCharASCII( bytes, pos, '\\' ) )
+ {
+ pos++;
+
+ if ( DNUtils.isPairChar( bytes, pos ) )
+ {
+ pos++;
+ }
+ else
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ }
+ else if ( (nbBytes = DNUtils.isQuoteChar( bytes, pos ) ) != -1 )
+ {
+ pos += nbBytes;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if ( StringUtils.isCharASCII( bytes, pos, '"' ) )
+ {
+ pos++;
+
+ return StringUtils.trimLeft( bytes, pos );
+ }
+ else
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ }
+ else
+ {
+ while ( true )
+ {
+ if ( StringUtils.isCharASCII( bytes, pos, '\\' ) )
+ {
+ // '\' <pairchar> <pairs-or-strings>
+ pos++;
+
+ if ( DNUtils.isPairChar( bytes, pos ) == false )
+ {
+ return -1;
+ }
+ else
+ {
+ pos++;
+ }
+ }
+ else
+ {
+ int nbBytes = 0;
+
+ // <stringchar> <pairs-or-strings>
+ if ( (nbBytes = DNUtils.isStringChar( bytes, pos )) != -1)
+ {
+ // A special case : if we have some spaces before the '+' character,
+ // we MUST skip them.
+ if ( StringUtils.isCharASCII( bytes, pos, ' ') )
+ {
+ pos = StringUtils.trimLeft( bytes, pos );
+
+ if ( ( DNUtils.isStringChar( bytes, pos ) == -1 ) &&
+ ( StringUtils.isCharASCII( bytes, pos, '\\' ) == false ) )
+ {
+ // Ok, we are done with the stringchar.
+ return pos;
+ }
+ }
+ else
+ {
+ // An unicode char could be more than one byte long
+ pos += nbBytes;
+ }
+ }
+ else
+ {
+ return pos;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Parse this rule : <br>
+ * <p>
+ * <attributeTypeAndValues> ::= <spaces> '+' <spaces> <attributeType> <spaces> '=' <spaces> <attributeValue> <attributeTypeAndValues> | e
+ * </p>
+ *
+ * @param chars The char buffer to parse
+ * @param pos The current position in the byte buffer
+ * @return The new position in the char buffer, or PARSING_ERROR if the rule does not apply to the char buffer
+ */
+ private static int parseAttributeTypeAndValues( char[] chars, int pos, LdapRDN rdn ) throws InvalidNameException
+ {
+ int newPos = 0;
+ MutableString type = null;
+ MutableString value = null;
+
+ while ( true )
+ {
+ pos = StringUtils.trimLeft( chars, pos );
+
+ if ( StringUtils.isCharASCII( chars, pos, '+' ) )
+ {
+ pos++;
+ }
+ else
+ {
+ // <attributeTypeAndValues> ::= e
+ return pos;
+ }
+
+ pos = StringUtils.trimLeft( chars, pos );
+
+ if ( ( newPos = parseAttributeType( chars, pos ) ) == DNUtils.PARSING_ERROR )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+
+ if ( rdn != null )
+ {
+ try
+ {
+ type = new MutableString( chars, pos, newPos - pos );
+ }
+ catch ( UnsupportedEncodingException uee )
+ {
+ throw new InvalidNameException( "Invalid UTF-8 String" );
+ }
+ }
+
+ pos = StringUtils.trimLeft( chars, newPos );
+
+ if ( StringUtils.isCharASCII( chars, pos, '=' ) )
+ {
+ pos++;
+ }
+ else
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+
+ pos = StringUtils.trimLeft( chars, pos );
+
+ newPos = parseAttributeValue( chars, pos );
+
+ if ( newPos != DNUtils.PARSING_ERROR )
+ {
+ if ( rdn != null )
+ {
+ try
+ {
+ value = new MutableString( chars, pos, newPos - pos );
+ }
+ catch ( UnsupportedEncodingException uee )
+ {
+ throw new InvalidNameException( "Invalid UTF-8 String" );
+ }
+
+ rdn.addNameComponent( type, value );
+ }
+ }
+
+ pos = newPos;
+ }
+ }
+
+ /**
+ * Parse this rule : <br>
+ * <p>
+ * <attributeTypeAndValues> ::= <spaces> '+' <spaces> <attributeType> <spaces> '=' <spaces> <attributeValue> <attributeTypeAndValues> | e
+ * </p>
+ *
+ * @param bytes The buffer to parse
+ * @param pos The current position in the byte buffer
+ * @return The new position in the byte buffer, or -1 if the rule does not apply to the byte buffer
+ */
+ private static int parseAttributeTypeAndValues( byte[] bytes, int pos, LdapRDN rdn ) throws InvalidNameException
+ {
+ int newPos = 0;
+ MutableString type = null;
+ MutableString value = null;
+
+ while ( true )
+ {
+ pos = StringUtils.trimLeft( bytes, pos );
+
+ if ( StringUtils.isCharASCII( bytes, pos, '+' ) )
+ {
+ pos++;
+ }
+ else
+ {
+ // <attributeTypeAndValues> ::= e
+ return pos;
+ }
+
+ pos = StringUtils.trimLeft( bytes, pos );
+
+ if ( ( newPos = parseAttributeType( bytes, pos ) ) == DNUtils.PARSING_ERROR )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+
+ if ( rdn != null )
+ {
+ try
+ {
+ type = new MutableString( bytes, pos, newPos - pos );
+ }
+ catch ( UnsupportedEncodingException uee )
+ {
+ throw new InvalidNameException( uee.getMessage() );
+ }
+ }
+
+ pos = StringUtils.trimLeft( bytes, pos );
+
+ if ( StringUtils.isCharASCII( bytes, pos, '=' ) )
+ {
+ pos++;
+ }
+ else
+ {
+
+ return DNUtils.PARSING_ERROR;
+ }
+
+ pos = StringUtils.trimLeft( bytes, pos );
+
+ newPos = parseAttributeValue( bytes, pos );
+
+ if ( newPos != DNUtils.PARSING_ERROR )
+ {
+ if ( rdn != null )
+ {
+ try
+ {
+ value = new MutableString( bytes, pos, newPos - pos );
+ }
+ catch ( UnsupportedEncodingException uee )
+ {
+ throw new InvalidNameException( uee.getMessage() );
+ }
+
+ rdn.addNameComponent( type, value );
+ }
+ }
+
+ pos = newPos;
+ }
+ }
+
+ /**
+ * Parse a NameComponent : <br>
+ * <p>
+ * <name-component> ::= <attributeType> <spaces> '=' <spaces> <attributeValue> <attributeTypeAndValues>
+ * </p>
+ *
+ * @param bytes The buffer to parse
+ * @param pos The current position in the buffer
+ * @return The new position in the char array, or PARSING_ERROR if the rule does not apply to the char array
+ */
+ public static int parseNameComponent( char[] chars, int pos, LdapRDN rdn ) throws InvalidNameException
+ {
+ int newPos = 0;
+ String type = null;
+ String value = null;
+
+ pos = StringUtils.trimLeft( chars, pos );
+
+ if ( ( newPos = parseAttributeType( chars, pos ) ) == DNUtils.PARSING_ERROR )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+
+ if ( rdn != null )
+ {
+ type = new String( chars, pos, newPos - pos );
+ }
+
+ pos = StringUtils.trimLeft( chars, newPos );
+
+ if ( StringUtils.isCharASCII( chars, pos, '=' ) == false )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ else
+ {
+ pos++;
+ }
+
+ pos = StringUtils.trimLeft( chars, pos );
+
+ if ( ( newPos = parseAttributeValue( chars, pos ) ) == DNUtils.PARSING_ERROR )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+
+ if ( rdn != null )
+ {
+ value = new String( chars, pos, newPos - pos );
+
+ rdn.addNameComponent( type, value );
+ }
+
+ return parseAttributeTypeAndValues( chars, newPos, rdn );
+ }
+
+ /**
+ * Parse a NameComponent : <br>
+ * <p>
+ * <name-component> ::= <attributeType> <spaces> '=' <spaces> <attributeValue> <attributeTypeAndValues>
+ * </p>
+ *
+ * @param string The buffer to parse
+ * @return The RDN, or null if the rule does not apply to the char array
+ */
+ public static LdapRDN parseNameComponent( String string ) throws InvalidNameException
+ {
+ LdapRDN rdn = new LdapRDN();
+
+ parseNameComponent( string.toCharArray(), 0, rdn );
+
+ return rdn;
+ }
+
+ /**
+ * Parse a NameComponent : <br>
+ * <p>
+ * <name-component> ::= <attributeType> <spaces> '=' <spaces> <attributeValue> <attributeTypeAndValues>
+ * </p>
+ *
+ * @param string The buffer to parse
+ * @param rdn The RDN to fill. Beware that if the RDN is not empty, the new NameComponent will be added.
+ * @return The RDN, or null if the rule does not apply to the char array
+ */
+ public static void parseNameComponent( String string, LdapRDN rdn ) throws InvalidNameException
+ {
+ parseNameComponent( string.toCharArray(), 0, rdn );
+ }
+
+ /**
+ * Parse a NameComponent : <br>
+ * <p>
+ * <name-component> ::= <attributeType> <spaces> '=' <spaces> <attributeValue> <attributeTypeAndValues>
+ * </p>
+ *
+ * @param bytes The buffer to parse
+ * @param pos The current position in the buffer
+ * @return The new position in the char array, or PARSING_ERROR if the rule does not apply to the char array
+ */
+ public static int parseNameComponent( byte[] bytes, int pos, LdapRDN rdn ) throws InvalidNameException
+ {
+ int newPos = 0;
+ MutableString type = null;
+ MutableString value = null;
+ rdn.normalizedName = new MutableString( bytes.length );
+
+ pos = StringUtils.trimLeft( bytes, pos );
+
+ if ( ( newPos = parseAttributeType( bytes, pos ) ) == DNUtils.PARSING_ERROR )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+
+ if ( rdn != null )
+ {
+ try
+ {
+ type = new MutableString( bytes, pos, newPos - pos );
+ rdn.normalizedName.append( type );
+ }
+ catch ( UnsupportedEncodingException uee )
+ {
+ throw new InvalidNameException( uee.getMessage() );
+ }
+
+ }
+
+ pos = StringUtils.trimLeft( bytes, newPos );
+
+ if ( StringUtils.isCharASCII( bytes, pos, '=' ) == false )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ else
+ {
+ pos++;
+ }
+
+ pos = StringUtils.trimLeft( bytes, pos );
+
+ if ( ( newPos = parseAttributeValue( bytes, pos ) ) == DNUtils.PARSING_ERROR )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+
+ if ( rdn != null )
+ {
+ try
+ {
+ value = new MutableString( bytes, pos, newPos - pos );
+ }
+ catch ( UnsupportedEncodingException uee )
+ {
+ throw new InvalidNameException( uee.getMessage() );
+ }
+
+ rdn.addNameComponent( type, value );
+ }
+
+ return parseAttributeTypeAndValues( bytes, newPos, rdn );
+ }
+
+ /**
+ * Clone the LdapRDN
+ */
+ public Object clone()
+ {
+ try
+ {
+ LdapRDN rdn = (LdapRDN)super.clone();
+
+ // The nameComponent is immutable. We won't clone it
+
+ if ( nameComponents != null )
+ {
+ nameComponents = (LinkedHashMap)((LinkedHashMap)this.nameComponents).clone();
+
+ Iterator values = nameComponents.values().iterator();
+
+ while ( values.hasNext() )
+ {
+ NameComponent nc = (NameComponent)values.next();
+ rdn.nameComponents.put( nc.getType(), nc );
+ }
+ }
+
+ return rdn;
+ }
+ catch ( CloneNotSupportedException cnse )
+ {
+ throw new Error( "Assertion failure" );
+ }
+ }
+
+ /**
+ * Returns a String representation of the RDN
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+
+ if ( nameComponents != null )
+ {
+ Iterator elems = nameComponents.values().iterator();
+ boolean isFirst = true;
+
+ while ( elems.hasNext() )
+ {
+ if ( isFirst )
+ {
+ isFirst = false;
+ }
+ else
+ {
+ sb.append( '+' );
+ }
+
+ sb.append( elems.next() );
+ }
+ }
+ else
+ {
+ if ( nameComponent != null )
+ {
+ sb.append( nameComponent );
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ return sb.toString();
+ }
+}
Added: directory/shared/ldap/branches/shared-ldap-NameComponent/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/NameComponent.java
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/branches/shared-ldap-NameComponent/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/NameComponent.java?rev=291833&view=auto
==============================================================================
--- directory/shared/ldap/branches/shared-ldap-NameComponent/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/NameComponent.java (added)
+++ directory/shared/ldap/branches/shared-ldap-NameComponent/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/NameComponent.java Mon Sep 26 23:52:40 2005
@@ -0,0 +1,230 @@
+/*
+ * 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.asn1new.ldap.codec.primitives;
+
+import java.io.UnsupportedEncodingException;
+
+import javax.naming.InvalidNameException;
+
+import org.apache.asn1new.util.MutableString;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * A name-component, which is the basis of all RDN.
+ * It contains a type, and a value.
+ *
+ * The type must not be case sensitive. Superfluous leading
+ * and trailing spaces MUST have been trimmed before.
+ *
+ * The value MUST be in UTF8 format, according to RFC 2253. If the type
+ * is in OID form, then the value must be a hexadecimal string prefixed
+ * by a '#' character. Otherwise, the string must respect the RC 2253
+ * grammar. No further normalization will be done, because we don't
+ * have any knowledge of the Schema definition in the parser.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class NameComponent implements Cloneable
+{
+ /** The Name type */
+ private MutableString type;
+
+ /** The name value */
+ private MutableString value;
+
+ /**
+ * Construct an empty NameComponent
+ */
+ public NameComponent()
+ {
+ type = null;
+ value = null;
+ }
+
+ /**
+ * Construct an NameComponent. The type and value are normalized :
+ * - the type is trimmed and lowercased
+ * - the value is trimmed
+ *
+ * @param type The type
+ * @param value the value
+ */
+ public NameComponent( String type, String value ) throws InvalidNameException
+ {
+ try
+ {
+ setTypeNormalized( new MutableString( type ) );
+ }
+ catch ( UnsupportedEncodingException uee )
+ {
+ throw new InvalidNameException( "The type is not a valid UTF-8 string" );
+ }
+
+ try
+ {
+ setValueNormalized( new MutableString( value ) );
+ }
+ catch ( UnsupportedEncodingException uee )
+ {
+ throw new InvalidNameException( "The value is not a valid UTF-8 string" );
+ }
+ }
+
+ /**
+ * Construct an NameComponent. The type and value are normalized :
+ * - the type is trimmed and lowercased
+ * - the value is trimmed
+ *
+ * @param type The type
+ * @param value the value
+ */
+ public NameComponent( MutableString type, MutableString value ) throws InvalidNameException
+ {
+ setTypeNormalized( type );
+ setValueNormalized( value );
+ }
+
+ /**
+ * Get the type of a NameComponent
+ *
+ * @return The type
+ */
+ public MutableString getType()
+ {
+ return type;
+ }
+
+ /**
+ * Store the type
+ *
+ * @param type The NameComponent type
+ */
+ public void setType( MutableString type ) throws InvalidNameException
+ {
+ if ( MutableString.isEmpty( type ) )
+ {
+ throw new InvalidNameException( "The NameComponent type cannot be null : " );
+ }
+
+ this.type = type;
+ }
+
+ /**
+ * Store the type
+ *
+ * @param type The NameComponent type
+ */
+ public void setType( String type ) throws InvalidNameException
+ {
+ if ( StringUtils.isEmpty( type ) )
+ {
+ throw new InvalidNameException( "The NameComponent type cannot be null" );
+ }
+
+ try
+ {
+ this.type = new MutableString( type );
+ }
+ catch ( UnsupportedEncodingException uee )
+ {
+ throw new InvalidNameException( "The NameComponent type is not a valid UTF-8 string" );
+ }
+ }
+
+ /**
+ * Store the type, after having trimmed and lowercased it.
+ *
+ * @param type The NameComponent type
+ */
+ public void setTypeNormalized( MutableString type ) throws InvalidNameException
+ {
+ this.type = MutableString.trim( type );
+ this.type.toLowerCase();
+
+ if ( MutableString.isEmpty( this.type ) )
+ {
+ throw new InvalidNameException( "The NameComponent type cannot be null : " );
+ }
+ }
+
+ /**
+ * Get the Value of a NameComponent
+ *
+ * @return The value
+ */
+ public MutableString getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Store the value of a NameComponent.
+ *
+ * @param value The value of the NameComponent
+ */
+ public void setValue( MutableString value )
+ {
+ this.value = MutableString.isEmpty( value ) ? MutableString.EMPTY_STRING : value;
+ }
+
+ /**
+ * Store the value of a NameComponent, after having trimmed it.
+ *
+ * @param value The value of the NameComponent
+ */
+ public void setValueNormalized( MutableString value )
+ {
+ this.value = MutableString.trim( value );
+
+ if ( MutableString.isEmpty( value ) )
+ {
+ this.value = MutableString.EMPTY_STRING;
+ }
+ }
+
+ /**
+ * Implements the cloning.
+ *
+ * @return a clone of this object
+ */
+ public Object clone()
+ {
+ try
+ {
+ return super.clone();
+ }
+ catch ( CloneNotSupportedException cnse )
+ {
+ throw new Error( "Assertion failure" );
+ }
+ }
+
+ /**
+ * A String representation of a NameComponent.
+ *
+ * @return A string representing a NameComponent
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append( type ).append( "=" ).append( value );
+
+ return sb.toString();
+ }
+}
+