/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* This class represents a relative distinguished name, or RDN, which is a
* component of a distinguished name as specified by
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>.
* An example of an RDN is "OU=Sales+CN=J.Smith". In this example,
* RDN is parsed as described in the class description for
* {@link javax.naming.ldap.LdapName <tt>LdapName</tt>}.
* <p>
* which can be viewed using
* {@link javax.naming.directory.Attributes Attributes}.
* In addition, it contains convenience methods that allow easy retrieval
* which is how it appears in a typical usage.
* It also contains helper methods that allow escaping of the unformatted
* attribute value and unescaping of the value formatted according to the
* escaping syntax defined in RFC2253. For methods that take or return
* attribute value as an Object, the value is either a String
* (in unescaped form) or a byte array.
* <p>
* <code>Rdn</code> will properly parse all valid RDNs, but
* does not attempt to detect all possible violations when parsing
* invalid RDNs. It is "generous" in accepting invalid RDNs.
* The "validity" of a name is determined ultimately when it
* is supplied to an LDAP server, which may accept or
* reject the name based on factors such as its schema information
* and interoperability considerations.
*
* <p>
* The following code example shows how to construct an Rdn using the
* constructor that takes type and value as arguments:
* <pre>
* Rdn rdn = new Rdn("cn", "Juicy, Fruit");
* System.out.println(rdn.toString());
* </pre>
* The last line will print <tt>cn=Juicy\, Fruit</tt>. The
* {@link #unescapeValue(String) <tt>unescapeValue()</tt>} method can be
* used to unescape the escaped comma resulting in the original
* value <tt>"Juicy, Fruit"</tt>. The {@link #escapeValue(Object)
* <tt>escapeValue()</tt>} method adds the escape back preceding the comma.
* <p>
* This class can be instantiated by a string representation
* of the RDN defined in RFC 2253 as shown in the following code example:
* <pre>
* Rdn rdn = new Rdn("cn=Juicy\\, Fruit");
* System.out.println(rdn.toString());
* </pre>
* The last line will print <tt>cn=Juicy\, Fruit</tt>.
* <p>
* Concurrent multithreaded read-only access of an instance of
* <tt>Rdn</tt> need not be synchronized.
* <p>
* Unless otherwise noted, the behavior of passing a null argument
* to a constructor or method in this class will cause NullPointerException
* to be thrown.
*
* @since 1.5
*/
// private transient ArrayList<RdnEntry> entries;
// The common case.
/**
* Constructs an Rdn from the given attribute set. See
* {@link javax.naming.directory.Attributes Attributes}.
* <p>
* The string attribute values are not interpretted as
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>
* formatted RDN strings. That is, the values are used
* literally (not parsed) and assumed to be unescaped.
*
* @param attrSet The non-null and non-empty attributes containing
* @throws InvalidNameException If contents of <tt>attrSet</tt> cannot
* be used to construct a valid RDN.
*/
throw new InvalidNameException("Attributes cannot be empty");
}
try {
}
} catch (NamingException e) {
e.getMessage());
throw e2;
}
sort(); // arrange entries for comparison
}
/**
* Constructs an Rdn from the given string.
* This constructor takes a string formatted according to the rules
* defined in <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>
* and described in the class description for
* {@link javax.naming.ldap.LdapName}.
*
* @param rdnString The non-null and non-empty RFC2253 formatted string.
* @throws InvalidNameException If a syntax error occurs during
* parsing of the rdnString.
*/
}
/**
* Constructs an Rdn from the given <tt>rdn</tt>.
* The contents of the <tt>rdn</tt> are simply copied into the newly
* created Rdn.
* @param rdn The non-null Rdn to be copied.
*/
}
/**
* Constructs an Rdn from the given attribute type and
* value.
* The string attribute values are not interpretted as
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>
* formatted RDN strings. That is, the values are used
* literally (not parsed) and assumed to be unescaped.
*
* @param type The non-null and non-empty string attribute type.
* @param value The non-null and non-empty attribute value.
* construct a valid RDN.
* @see #toString()
*/
throw new NullPointerException("Cannot set value to null");
}
throw new InvalidNameException(
"type or value cannot be empty, type:" + type +
" value:" + value);
}
}
}
// An empty constructor used by the parser
Rdn() {
}
/*
* Adds the given attribute type and value to this Rdn.
* The string attribute values are not interpretted as
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>
* formatted RDN strings. That is the values are used
* literally (not parsed) and assumed to be unescaped.
*
* @param type The non-null and non-empty string attribute type.
* @param value The non-null and non-empty attribute value.
* @return The updated Rdn, not a new one. Cannot be null.
* @see #toString()
*/
// create new Entry
if (value instanceof byte[]) { // clone the byte array
} else {
}
return this;
}
void sort() {
}
}
/**
* Retrieves one of this Rdn's value.
* This is a convenience method for obtaining the value,
* when the RDN contains a single type and value mapping,
* which is the common RDN usage.
* <p>
* For a multi-valued RDN, this method returns value corresponding
* to the type returned by {@link #getType() getType()} method.
*
* @return The non-null attribute value.
*/
}
/**
* Retrieves one of this Rdn's type.
* This is a convenience method for obtaining the type,
* when the RDN contains a single type and value mapping,
* which is the common RDN usage.
* <p>
* no specific order defined on them. In that case, this method
* The {@link #getValue() getValue()} method returns the
* value corresponding to the type returned by this method.
*
* @return The non-null attribute type.
*/
}
/**
* Returns this Rdn as a string represented in a format defined by
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a> and described
* in the class description for {@link javax.naming.ldap.LdapName LdapName}.
*
* @return The string representation of the Rdn.
*/
if (size > 0) {
}
}
}
/**
* Compares this Rdn with the specified Object for order.
* Returns a negative integer, zero, or a positive integer as this
* Rdn is less than, equal to, or greater than the given Object.
* <p>
* If obj is null or not an instance of Rdn, ClassCastException
* is thrown.
* <p>
* The attribute type and value pairs of the RDNs are lined up
* against each other and compared lexicographically. The order of
* components in multi-valued Rdns (such as "ou=Sales+cn=Bob") is not
* significant.
*
* @param obj The non-null object to compare against.
* @return A negative integer, zero, or a positive integer as this Rdn
* is less than, equal to, or greater than the given Object.
* @exception ClassCastException if obj is null or not a Rdn.
* <p>
*/
throw new ClassCastException("The obj is not a Rdn");
}
if (obj == this) {
return 0;
}
for (int i = 0; i < minSize; i++) {
if (diff != 0) {
return diff;
}
}
}
/**
* 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 (such as "ou=Sales+cn=Bob") is not
* significant.
* <p>
* Type and value equalilty matching is done as below:
* <ul>
* <li> The types are compared for equality with their case ignored.
* <li> String values with different but equivalent usage of quoting,
* escaping, or UTF8-hex-encoding are considered equal.
* The case of the values is ignored during the comparison.
* </ul>
* <p>
* If obj is null or not an instance of Rdn, false is returned.
* <p>
* @param obj object to be compared for equality with this Rdn.
* @return true if the specified object is equal to this Rdn.
* @see #hashCode()
*/
if (obj == this) {
return true;
}
return false;
}
return false;
}
return false;
}
}
return true;
}
/**
* Returns the hash code of this RDN. Two RDNs that are
* equal (according to the equals method) will have the same
* hash code.
*
* @return An int representing the hash code of this Rdn.
* @see #equals
*/
public int hashCode() {
// Sum up the hash codes of the components.
int hash = 0;
}
return hash;
}
/**
* Retrieves the {@link javax.naming.directory.Attributes Attributes}
*
* mappings of this Rdn.
*/
}
}
return attrs;
}
// If non-null, a cannonical representation of the value suitable
// for comparison using String.compareTo()
return type;
}
return value;
}
// Any change here affecting equality must be
// reflected in hashCode().
if (diff != 0) {
return diff;
}
return 0;
}
return getValueComparable().compareTo(
}
if (obj == this) {
return true;
}
return false;
}
// Any change here must be reflected in hashCode()
that.getValueComparable()));
}
public int hashCode() {
getValueComparable().hashCode());
}
}
if (comparable != null) {
return comparable; // return cached result
}
// cache result
if (value instanceof byte[]) {
} else {
}
return comparable;
}
}
/**
*/
public int size() {
}
/**
* Given the value of an attribute, returns a string escaped according
* to the rules specified in
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>.
* <p>
* For example, if the val is "Sue, Grabbit and Runn", the escaped
* value returned by this method is "Sue\, Grabbit and Runn".
* <p>
* A string value is represented as a String and binary value
* as a byte array.
*
* @param val The non-null object to be escaped.
* @return Escaped string value.
* @throws ClassCastException if val is is not a String or byte array.
*/
return (val instanceof byte[])
? escapeBinaryValue((byte[])val)
}
/*
* Given the value of a string-valued attribute, returns a
* string suitable for inclusion in a DN. This is accomplished by
* using backslash (\) to escape the following characters:
* leading and trailing whitespace
* , = + < > # ; " \
*/
// Find leading and trailing whitespace.
int lead; // index of first char that is not leading whitespace
break;
}
}
int trail; // index of last char that is not trailing whitespace
break;
}
}
char c = chars[i];
}
}
}
/*
* Given the value of a binary attribute, returns a string
* suitable for inclusion in a DN (such as "#CEB1DF80").
* TBD: This method should actually generate the ber encoding
* of the binary value
*/
byte b = val[i];
}
// return builder.toString().toUpperCase();
}
/**
* Given an attribute value string formated according to the rules
* specified in
* <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>,
* returns the unformated value. Escapes and quotes are
* stripped away, and hex-encoded UTF-8 is converted to equivalent
* UTF-16 characters. Returns a string value as a String, and a
* binary value as a byte array.
* <p>
* Legal and illegal values are defined in RFC 2253.
* This method is generous in accepting the values and does not
* catch all illegal values.
* Therefore, passing in an illegal value might not necessarily
* trigger an <tt>IllegalArgumentException</tt>.
*
* @param val The non-null string to be unescaped.
* @return Unescaped value.
* @throws IllegalArgumentException When an Illegal value
* is provided.
*/
int beg = 0;
// Trim off leading and trailing whitespace.
++beg;
}
--end;
}
// Add back the trailing whitespace with a preceeding '\'
// (escaped or unescaped) that was taken off in the above
// loop. Whether or not to retain this whitespace is decided below.
end++;
}
return "";
}
// Value is binary (eg: "#CEB1DF80").
}
// Trim off quotes.
++beg;
--end;
}
++i; // skip backslash
esc = i;
} else {
// Convert hex-encoded UTF-8 to 16-bit chars.
try {
// shouldn't happen
}
} else { // no utf8 bytes available, invalid DN
// '/' has no meaning, throw exception
throw new IllegalArgumentException(
"Not a valid attribute string value:" +
val + ",improper usage of backslash");
}
}
} else {
}
}
// Get rid of the unescaped trailing whitespace with the
// preceeding '\' character that was previously added back.
}
}
/*
* Given an array of chars (with starting and ending indexes into it)
* representing bytes encoded as hex-pairs (such as "CEB1DF80"),
* returns a byte array containing the decoded bytes.
*/
break;
}
beg += 2;
}
throw new IllegalArgumentException(
}
return bytes;
}
/*
* Given an array of chars (with starting and ending indexes into it),
* finds the largest prefix consisting of hex-encoded UTF-8 octets,
* and returns a byte array containing the corresponding UTF-8 octets.
*
* Hex-encoded UTF-8 octets look like this:
* \03\B1\DF\80
*/
break;
}
}
return utf8;
} else {
return res;
}
}
/*
* Best guess as to what RFC 2253 means by "whitespace".
*/
private static boolean isWhitespace(char c) {
return (c == ' ' || c == '\r');
}
/**
* Serializes only the unparsed RDN, for compactness and to avoid
* any implementation dependency.
*
* @serialData The RDN string
*/
s.defaultWriteObject();
s.writeObject(toString());
}
throws IOException, ClassNotFoundException {
s.defaultReadObject();
try {
} catch (InvalidNameException e) {
// shouldn't happen
"Invalid name: " + unparsed);
}
}
}