Source Code Cross Referenced for Rdn.java in  » 6.0-JDK-Core » naming » javax » naming » ldap » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » naming » javax.naming.ldap 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001        /*
002         * Copyright 2003-2005 Sun Microsystems, Inc.  All Rights Reserved.
003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004         *
005         * This code is free software; you can redistribute it and/or modify it
006         * under the terms of the GNU General Public License version 2 only, as
007         * published by the Free Software Foundation.  Sun designates this
008         * particular file as subject to the "Classpath" exception as provided
009         * by Sun in the LICENSE file that accompanied this code.
010         *
011         * This code is distributed in the hope that it will be useful, but WITHOUT
012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014         * version 2 for more details (a copy is included in the LICENSE file that
015         * accompanied this code).
016         *
017         * You should have received a copy of the GNU General Public License version
018         * 2 along with this work; if not, write to the Free Software Foundation,
019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020         *
021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022         * CA 95054 USA or visit www.sun.com if you need additional information or
023         * have any questions.
024         */
025
026        package javax.naming.ldap;
027
028        import java.util.Iterator;
029        import java.util.NoSuchElementException;
030        import java.util.ArrayList;
031        import java.util.Collections;
032
033        import javax.naming.InvalidNameException;
034        import javax.naming.directory.BasicAttributes;
035        import javax.naming.directory.Attributes;
036        import javax.naming.directory.Attribute;
037        import javax.naming.NamingEnumeration;
038        import javax.naming.NamingException;
039
040        import java.io.Serializable;
041        import java.io.ObjectOutputStream;
042        import java.io.ObjectInputStream;
043        import java.io.IOException;
044
045        /**
046         * This class represents a relative distinguished name, or RDN, which is a
047         * component of a distinguished name as specified by
048         * <a href="http://ietf.org/rfc/rfc2253.txt">RFC 2253</a>.
049         * An example of an RDN is "OU=Sales+CN=J.Smith". In this example,
050         * the RDN consist of multiple attribute type/value pairs. The
051         * RDN is parsed as described in the class description for
052         * {@link javax.naming.ldap.LdapName <tt>LdapName</tt>}.
053         * <p>
054         * The Rdn class represents an RDN as attribute type/value mappings,
055         * which can be viewed using
056         * {@link javax.naming.directory.Attributes Attributes}.
057         * In addition, it contains convenience methods that allow easy retrieval
058         * of type and value when the Rdn consist of a single type/value pair,
059         * which is how it appears in a typical usage.
060         * It also contains helper methods that allow escaping of the unformatted
061         * attribute value and unescaping of the value formatted according to the
062         * escaping syntax defined in RFC2253. For methods that take or return
063         * attribute value as an Object, the value is either a String
064         * (in unescaped form) or a byte array.
065         * <p>
066         * <code>Rdn</code> will properly parse all valid RDNs, but
067         * does not attempt to detect all possible violations when parsing
068         * invalid RDNs. It is "generous" in accepting invalid RDNs.
069         * The "validity" of a name is determined ultimately when it
070         * is supplied to an LDAP server, which may accept or
071         * reject the name based on factors such as its schema information
072         * and interoperability considerations.
073         *
074         * <p>
075         * The following code example shows how to construct an Rdn using the
076         * constructor that takes type and value as arguments:
077         * <pre>
078         *	Rdn rdn = new Rdn("cn", "Juicy, Fruit");
079         *	System.out.println(rdn.toString());
080         * </pre>
081         * The last line will print <tt>cn=Juicy\, Fruit</tt>. The
082         * {@link #unescapeValue(String) <tt>unescapeValue()</tt>} method can be
083         * used to unescape the escaped comma resulting in the original
084         * value <tt>"Juicy, Fruit"</tt>. The {@link #escapeValue(Object)
085         * <tt>escapeValue()</tt>} method adds the escape back preceding the comma.
086         * <p>
087         * This class can be instantiated by a string representation
088         * of the RDN defined in RFC 2253 as shown in the following code example:
089         * <pre>
090         * 	Rdn rdn = new Rdn("cn=Juicy\\, Fruit");
091         *	System.out.println(rdn.toString());
092         * </pre>
093         * The last line will print <tt>cn=Juicy\, Fruit</tt>.
094         * <p>
095         * Concurrent multithreaded read-only access of an instance of
096         * <tt>Rdn</tt> need not be synchronized.
097         * <p>
098         * Unless otherwise noted, the behavior of passing a null argument
099         * to a constructor or method in this class will cause NullPointerException
100         * to be thrown.
101         *
102         * @version 1.15 07/05/05
103         * @since 1.5
104         */
105
106        public class Rdn implements  Serializable, Comparable<Object> {
107
108            // private transient ArrayList<RdnEntry> entries;
109            private transient ArrayList entries;
110
111            // The common case.
112            private static final int DEFAULT_SIZE = 1;
113
114            private static final long serialVersionUID = -5994465067210009656L;
115
116            /**
117             * Constructs an Rdn from the given attribute set. See
118             * {@link javax.naming.directory.Attributes Attributes}.
119             * <p>
120             * The string attribute values are not interpretted as
121             * <a href="http://ietf.org/rfc/rfc2253.txt">RFC 2253</a>
122             * formatted RDN strings. That is, the values are used
123             * literally (not parsed) and assumed to be unescaped.
124             *
125             * @param attrSet The non-null and non-empty attributes containing
126             * type/value mappings.
127             * @throws InvalidNameException If contents of <tt>attrSet</tt> cannot
128             * 		be used to construct a valid RDN.
129             */
130            public Rdn(Attributes attrSet) throws InvalidNameException {
131                if (attrSet.size() == 0) {
132                    throw new InvalidNameException("Attributes cannot be empty");
133                }
134                entries = new ArrayList(attrSet.size());
135                NamingEnumeration attrs = attrSet.getAll();
136                try {
137                    for (int nEntries = 0; attrs.hasMore(); nEntries++) {
138                        RdnEntry entry = new RdnEntry();
139                        Attribute attr = (Attribute) attrs.next();
140                        entry.type = attr.getID();
141                        entry.value = attr.get();
142                        entries.add(nEntries, entry);
143                    }
144                } catch (NamingException e) {
145                    InvalidNameException e2 = new InvalidNameException(e
146                            .getMessage());
147                    e2.initCause(e);
148                    throw e2;
149                }
150                sort(); // arrange entries for comparison
151            }
152
153            /**
154             * Constructs an Rdn from the given string.
155             * This constructor takes a string formatted according to the rules
156             * defined in <a href="http://ietf.org//rfc/rfc2253.txt">RFC 2253</a>
157             * and described in the class description for
158             * {@link javax.naming.ldap.LdapName}.
159             *
160             * @param rdnString	The non-null and non-empty RFC2253 formatted string.
161             * @throws InvalidNameException If a syntax error occurs during
162             * 			parsing of the rdnString.
163             */
164            public Rdn(String rdnString) throws InvalidNameException {
165                entries = new ArrayList(DEFAULT_SIZE);
166                (new Rfc2253Parser(rdnString)).parseRdn(this );
167            }
168
169            /**
170             * Constructs an Rdn from the given <tt>rdn</tt>.
171             * The contents of the <tt>rdn</tt> are simply copied into the newly
172             * created Rdn.
173             * @param rdn The non-null Rdn to be copied.
174             */
175            public Rdn(Rdn rdn) {
176                entries = new ArrayList(rdn.entries.size());
177                entries.addAll(rdn.entries);
178            }
179
180            /**
181             * Constructs an Rdn from the given attribute type and
182             * value.
183             * The string attribute values are not interpretted as
184             * <a href="http://ietf.org/rfc/rfc2253.txt">RFC 2253</a>
185             * formatted RDN strings. That is, the values are used
186             * literally (not parsed) and assumed to be unescaped.
187             *
188             * @param type The non-null and non-empty string attribute type.
189             * @param value The non-null and non-empty attribute value.
190             * @throws InvalidNameException If type/value cannot be used to
191             *			construct a valid RDN.
192             * @see #toString()
193             */
194            public Rdn(String type, Object value) throws InvalidNameException {
195                if (value == null) {
196                    throw new NullPointerException("Cannot set value to null");
197                }
198                if (type.equals("") || isEmptyValue(value)) {
199                    throw new InvalidNameException(
200                            "type or value cannot be empty, type:" + type
201                                    + " value:" + value);
202                }
203                entries = new ArrayList(DEFAULT_SIZE);
204                put(type, value);
205            }
206
207            private boolean isEmptyValue(Object val) {
208                return ((val instanceof  String) && val.equals(""))
209                        || ((val instanceof  byte[]) && (((byte[]) val).length == 0));
210            }
211
212            // An empty constructor used by the parser
213            Rdn() {
214                entries = new ArrayList(DEFAULT_SIZE);
215            }
216
217            /*
218             * Adds the given attribute type and value to this Rdn.
219             * The string attribute values are not interpretted as
220             * <a href="http://ietf.org/rfc/rfc2253.txt">RFC 2253</a>
221             * formatted RDN strings. That is the values are used
222             * literally (not parsed) and assumed to be unescaped.
223             *
224             * @param type The non-null and non-empty string attribute type.
225             * @param value The non-null and non-empty attribute value.
226             * @return The updated Rdn, not a new one. Cannot be null.
227             * @see #toString()
228             */
229            Rdn put(String type, Object value) {
230
231                // create new Entry
232                RdnEntry newEntry = new RdnEntry();
233                newEntry.type = type;
234                if (value instanceof  byte[]) { // clone the byte array
235                    newEntry.value = ((byte[]) value).clone();
236                } else {
237                    newEntry.value = value;
238                }
239                entries.add(newEntry);
240                return this ;
241            }
242
243            void sort() {
244                if (entries.size() > 1) {
245                    Collections.sort(entries);
246                }
247            }
248
249            /**
250             * Retrieves one of this Rdn's value.
251             * This is a convenience method for obtaining the value,
252             * when the RDN contains a single type and value mapping,
253             * which is the common RDN usage.
254             * <p>
255             * For a multi-valued RDN, this method returns value corresponding
256             * to the type returned by {@link #getType() getType()} method.
257             *
258             * @return The non-null attribute value.
259             */
260            public Object getValue() {
261                return ((RdnEntry) entries.get(0)).getValue();
262            }
263
264            /**
265             * Retrieves one of this Rdn's type.
266             * This is a convenience method for obtaining the type,
267             * when the RDN contains a single type and value mapping,
268             * which is the common RDN usage.
269             * <p>
270             * For a multi-valued RDN, the type/value pairs have
271             * no specific order defined on them. In that case, this method
272             * returns type of one of the type/value pairs.
273             * The {@link #getValue() getValue()} method returns the
274             * value corresponding to the type returned by this method.
275             *
276             * @return The non-null attribute type.
277             */
278            public String getType() {
279                return ((RdnEntry) entries.get(0)).getType();
280            }
281
282            /**
283             * Returns this Rdn as a string represented in a format defined by
284             * <a href="http://ietf.org//rfc/rfc2253.txt">RFC 2253</a> and described
285             * in the class description for {@link javax.naming.ldap.LdapName LdapName}.
286             *
287             * @return The string representation of the Rdn.
288             */
289            public String toString() {
290                StringBuilder builder = new StringBuilder();
291                int size = entries.size();
292                if (size > 0) {
293                    builder.append(entries.get(0));
294                }
295                for (int next = 1; next < size; next++) {
296                    builder.append('+');
297                    builder.append(entries.get(next));
298                }
299                return builder.toString();
300            }
301
302            /**
303             * Compares this Rdn with the specified Object for order.
304             * Returns a negative integer, zero, or a positive integer as this
305             * Rdn is less than, equal to, or greater than the given Object.
306             * <p>
307             * If obj is null or not an instance of Rdn, ClassCastException
308             * is thrown.
309             * <p>
310             * The attribute type and value pairs of the RDNs are lined up
311             * against each other and compared lexicographically. The order of
312             * components in multi-valued Rdns (such as "ou=Sales+cn=Bob") is not
313             * significant.
314             *
315             * @param obj The non-null object to compare against.
316             * @return  A negative integer, zero, or a positive integer as this Rdn
317             * 		is less than, equal to, or greater than the given Object.
318             * @exception ClassCastException if obj is null or not a Rdn.
319             * <p>
320             */
321            public int compareTo(Object obj) {
322                if (!(obj instanceof  Rdn)) {
323                    throw new ClassCastException("The obj is not a Rdn");
324                }
325                if (obj == this ) {
326                    return 0;
327                }
328                Rdn that = (Rdn) obj;
329                int minSize = Math.min(entries.size(), that.entries.size());
330                for (int i = 0; i < minSize; i++) {
331
332                    // Compare a single pair of type/value pairs.
333                    int diff = ((RdnEntry) entries.get(i))
334                            .compareTo(that.entries.get(i));
335                    if (diff != 0) {
336                        return diff;
337                    }
338                }
339                return (entries.size() - that.entries.size()); // longer RDN wins
340            }
341
342            /**
343             * Compares the specified Object with this Rdn for equality.
344             * Returns true if the given object is also a Rdn and the two Rdns
345             * represent the same attribute type and value mappings. The order of
346             * components in multi-valued Rdns (such as "ou=Sales+cn=Bob") is not
347             * significant.
348             * <p>
349             * Type and value equalilty matching is done as below:
350             * <ul>
351             * <li> The types are compared for equality with their case ignored.
352             * <li> String values with different but equivalent usage of quoting,
353             * escaping, or UTF8-hex-encoding are considered equal.
354             * The case of the values is ignored during the comparison.
355             * </ul>
356             * <p>
357             * If obj is null or not an instance of Rdn, false is returned.
358             * <p>
359             * @param obj object to be compared for equality with this Rdn.
360             * @return true if the specified object is equal to this Rdn.
361             * @see #hashCode()
362             */
363            public boolean equals(Object obj) {
364                if (obj == this ) {
365                    return true;
366                }
367                if (!(obj instanceof  Rdn)) {
368                    return false;
369                }
370                Rdn that = (Rdn) obj;
371                if (entries.size() != that.size()) {
372                    return false;
373                }
374                for (int i = 0; i < entries.size(); i++) {
375                    if (!entries.get(i).equals(that.entries.get(i))) {
376                        return false;
377                    }
378                }
379                return true;
380            }
381
382            /**
383             * Returns the hash code of this RDN. Two RDNs that are
384             * equal (according to the equals method) will have the same
385             * hash code.
386             *
387             * @return An int representing the hash code of this Rdn.
388             * @see #equals
389             */
390            public int hashCode() {
391
392                // Sum up the hash codes of the components.
393                int hash = 0;
394
395                // For each type/value pair...
396                for (int i = 0; i < entries.size(); i++) {
397                    hash += entries.get(i).hashCode();
398                }
399                return hash;
400            }
401
402            /**
403             * Retrieves the {@link javax.naming.directory.Attributes Attributes}
404             * view of the type/value mappings contained in this Rdn.
405             *
406             * @return 	The non-null attributes containing the type/value
407             *		mappings of this Rdn.
408             */
409            public Attributes toAttributes() {
410                Attributes attrs = new BasicAttributes(true);
411                for (int i = 0; i < entries.size(); i++) {
412                    RdnEntry entry = (RdnEntry) entries.get(i);
413                    Attribute attr = attrs.put(entry.getType(), entry
414                            .getValue());
415                    if (attr != null) {
416                        attr.add(entry.getValue());
417                        attrs.put(attr);
418                    }
419                }
420                return attrs;
421            }
422
423            private static class RdnEntry implements  Comparable {
424                private String type;
425                private Object value;
426
427                // If non-null, a cannonical representation of the value suitable
428                // for comparison using String.compareTo()
429                private String comparable = null;
430
431                String getType() {
432                    return type;
433                }
434
435                Object getValue() {
436                    return value;
437                }
438
439                public int compareTo(Object obj) {
440
441                    // Any change here affecting equality must be
442                    // reflected in hashCode().
443                    RdnEntry that = (RdnEntry) obj;
444
445                    int diff = type.toUpperCase().compareTo(
446                            that.type.toUpperCase());
447                    if (diff != 0) {
448                        return diff;
449                    }
450                    if (value.equals(that.value)) { // try shortcut
451                        return 0;
452                    }
453                    return getValueComparable().compareTo(
454                            that.getValueComparable());
455                }
456
457                public boolean equals(Object obj) {
458                    if (obj == this ) {
459                        return true;
460                    }
461                    if (!(obj instanceof  RdnEntry)) {
462                        return false;
463                    }
464
465                    // Any change here must be reflected in hashCode()
466                    RdnEntry that = (RdnEntry) obj;
467                    return (type.equalsIgnoreCase(that.type))
468                            && (getValueComparable().equals(that
469                                    .getValueComparable()));
470                }
471
472                public int hashCode() {
473                    return (type.toUpperCase().hashCode() + getValueComparable()
474                            .hashCode());
475                }
476
477                public String toString() {
478                    return type + "=" + escapeValue(value);
479                }
480
481                private String getValueComparable() {
482                    if (comparable != null) {
483                        return comparable; // return cached result
484                    }
485
486                    // cache result
487                    if (value instanceof  byte[]) {
488                        comparable = escapeBinaryValue((byte[]) value);
489                    } else {
490                        comparable = ((String) value).toUpperCase();
491                    }
492                    return comparable;
493                }
494            }
495
496            /**
497             * Retrieves the number of attribute type/value pairs in this Rdn.
498             * @return The non-negative number of type/value pairs in this Rdn.
499             */
500            public int size() {
501                return entries.size();
502            }
503
504            /**
505             * Given the value of an attribute, returns a string escaped according
506             * to the rules specified in
507             * <a href="http://ietf.org/rfc/rfc2253.txt">RFC 2253</a>.
508             * <p>
509             * For example, if the val is "Sue, Grabbit and Runn", the escaped
510             * value returned by this method is "Sue\, Grabbit and Runn".
511             * <p>
512             * A string value is represented as a String and binary value
513             * as a byte array.
514             *
515             * @param val The non-null object to be escaped.
516             * @return Escaped string value.
517             * @throws ClassCastException if val is is not a String or byte array.
518             */
519            public static String escapeValue(Object val) {
520                return (val instanceof  byte[]) ? escapeBinaryValue((byte[]) val)
521                        : escapeStringValue((String) val);
522            }
523
524            /*
525             * Given the value of a string-valued attribute, returns a
526             * string suitable for inclusion in a DN.  This is accomplished by
527             * using backslash (\) to escape the following characters:
528             *	leading and trailing whitespace
529             *	, = + < > # ; " \
530             */
531            private static final String escapees = ",=+<>#;\"\\";
532
533            private static String escapeStringValue(String val) {
534
535                char[] chars = val.toCharArray();
536                StringBuilder builder = new StringBuilder(2 * val.length());
537
538                // Find leading and trailing whitespace.
539                int lead; // index of first char that is not leading whitespace
540                for (lead = 0; lead < chars.length; lead++) {
541                    if (!isWhitespace(chars[lead])) {
542                        break;
543                    }
544                }
545                int trail; // index of last char that is not trailing whitespace
546                for (trail = chars.length - 1; trail >= 0; trail--) {
547                    if (!isWhitespace(chars[trail])) {
548                        break;
549                    }
550                }
551
552                for (int i = 0; i < chars.length; i++) {
553                    char c = chars[i];
554                    if ((i < lead) || (i > trail) || (escapees.indexOf(c) >= 0)) {
555                        builder.append('\\');
556                    }
557                    builder.append(c);
558                }
559                return builder.toString();
560            }
561
562            /*
563             * Given the value of a binary attribute, returns a string
564             * suitable for inclusion in a DN (such as "#CEB1DF80").
565             * TBD: This method should actually generate the ber encoding
566             * of the binary value
567             */
568            private static String escapeBinaryValue(byte[] val) {
569
570                StringBuilder builder = new StringBuilder(1 + 2 * val.length);
571                builder.append("#");
572
573                for (int i = 0; i < val.length; i++) {
574                    byte b = val[i];
575                    builder.append(Character.forDigit(0xF & (b >>> 4), 16));
576                    builder.append(Character.forDigit(0xF & b, 16));
577                }
578                return builder.toString();
579                // return builder.toString().toUpperCase();
580            }
581
582            /**
583             * Given an attribute value string formated according to the rules
584             * specified in
585             * <a href="http://ietf.org//rfc/rfc2253.txt">RFC 2253</a>,
586             * returns the unformated value.  Escapes and quotes are
587             * stripped away, and hex-encoded UTF-8 is converted to equivalent
588             * UTF-16 characters. Returns a string value as a String, and a
589             * binary value as a byte array.
590             * <p>
591             * Legal and illegal values are defined in RFC 2253.
592             * This method is generous in accepting the values and does not
593             * catch all illegal values.
594             * Therefore, passing in an illegal value might not necessarily
595             * trigger an <tt>IllegalArgumentException</tt>.
596             *
597             * @param	val	The non-null string to be unescaped.
598             * @return 		Unescaped value.
599             * @throws 		IllegalArgumentException When an Illegal value
600             *			is provided.
601             */
602            public static Object unescapeValue(String val) {
603
604                char[] chars = val.toCharArray();
605                int beg = 0;
606                int end = chars.length;
607
608                // Trim off leading and trailing whitespace.
609                while ((beg < end) && isWhitespace(chars[beg])) {
610                    ++beg;
611                }
612
613                while ((beg < end) && isWhitespace(chars[end - 1])) {
614                    --end;
615                }
616
617                // Add back the trailing whitespace with a preceeding '\'
618                // (escaped or unescaped) that was taken off in the above
619                // loop. Whether or not to retain this whitespace is decided below.
620                if (end != chars.length && (beg < end)
621                        && chars[end - 1] == '\\') {
622                    end++;
623                }
624                if (beg >= end) {
625                    return "";
626                }
627
628                if (chars[beg] == '#') {
629                    // Value is binary (eg: "#CEB1DF80").
630                    return decodeHexPairs(chars, ++beg, end);
631                }
632
633                // Trim off quotes.
634                if ((chars[beg] == '\"') && (chars[end - 1] == '\"')) {
635                    ++beg;
636                    --end;
637                }
638
639                StringBuilder builder = new StringBuilder(end - beg);
640                int esc = -1; // index of the last escaped character
641
642                for (int i = beg; i < end; i++) {
643                    if ((chars[i] == '\\') && (i + 1 < end)) {
644                        if (!Character.isLetterOrDigit(chars[i + 1])) {
645                            ++i; // skip backslash
646                            builder.append(chars[i]); // snarf escaped char
647                            esc = i;
648                        } else {
649
650                            // Convert hex-encoded UTF-8 to 16-bit chars.
651                            byte[] utf8 = getUtf8Octets(chars, i, end);
652                            if (utf8.length > 0) {
653                                try {
654                                    builder.append(new String(utf8, "UTF8"));
655                                } catch (java.io.UnsupportedEncodingException e) {
656                                    // shouldn't happen
657                                }
658                                i += utf8.length * 3 - 1;
659                            } else { // no utf8 bytes available, invalid DN
660
661                                // '/' has no meaning, throw exception
662                                throw new IllegalArgumentException(
663                                        "Not a valid attribute string value:"
664                                                + val
665                                                + ",improper usage of backslash");
666                            }
667                        }
668                    } else {
669                        builder.append(chars[i]); // snarf unescaped char
670                    }
671                }
672
673                // Get rid of the unescaped trailing whitespace with the
674                // preceeding '\' character that was previously added back.
675                int len = builder.length();
676                if (isWhitespace(builder.charAt(len - 1)) && esc != (end - 1)) {
677                    builder.setLength(len - 1);
678                }
679                return builder.toString();
680            }
681
682            /*
683             * Given an array of chars (with starting and ending indexes into it)
684             * representing bytes encoded as hex-pairs (such as "CEB1DF80"),
685             * returns a byte array containing the decoded bytes.
686             */
687            private static byte[] decodeHexPairs(char[] chars, int beg, int end) {
688                byte[] bytes = new byte[(end - beg) / 2];
689                for (int i = 0; beg + 1 < end; i++) {
690                    int hi = Character.digit(chars[beg], 16);
691                    int lo = Character.digit(chars[beg + 1], 16);
692                    if (hi < 0 || lo < 0) {
693                        break;
694                    }
695                    bytes[i] = (byte) ((hi << 4) + lo);
696                    beg += 2;
697                }
698                if (beg != end) {
699                    throw new IllegalArgumentException(
700                            "Illegal attribute value: " + new String(chars));
701                }
702                return bytes;
703            }
704
705            /*
706             * Given an array of chars (with starting and ending indexes into it),
707             * finds the largest prefix consisting of hex-encoded UTF-8 octets,
708             * and returns a byte array containing the corresponding UTF-8 octets.
709             *
710             * Hex-encoded UTF-8 octets look like this:
711             *	\03\B1\DF\80
712             */
713            private static byte[] getUtf8Octets(char[] chars, int beg, int end) {
714                byte[] utf8 = new byte[(end - beg) / 3]; // allow enough room
715                int len = 0; // index of first unused byte in utf8
716
717                while ((beg + 2 < end) && (chars[beg++] == '\\')) {
718                    int hi = Character.digit(chars[beg++], 16);
719                    int lo = Character.digit(chars[beg++], 16);
720                    if (hi < 0 || lo < 0) {
721                        break;
722                    }
723                    utf8[len++] = (byte) ((hi << 4) + lo);
724                }
725                if (len == utf8.length) {
726                    return utf8;
727                } else {
728                    byte[] res = new byte[len];
729                    System.arraycopy(utf8, 0, res, 0, len);
730                    return res;
731                }
732            }
733
734            /*
735             * Best guess as to what RFC 2253 means by "whitespace".
736             */
737            private static boolean isWhitespace(char c) {
738                return (c == ' ' || c == '\r');
739            }
740
741            /**
742             * Serializes only the unparsed RDN, for compactness and to avoid
743             * any implementation dependency.
744             *
745             * @serialData	The RDN string
746             */
747            private void writeObject(ObjectOutputStream s)
748                    throws java.io.IOException {
749                s.defaultWriteObject();
750                s.writeObject(toString());
751            }
752
753            private void readObject(ObjectInputStream s) throws IOException,
754                    ClassNotFoundException {
755                s.defaultReadObject();
756                entries = new ArrayList(DEFAULT_SIZE);
757                String unparsed = (String) s.readObject();
758                try {
759                    (new Rfc2253Parser(unparsed)).parseRdn(this );
760                } catch (InvalidNameException e) {
761                    // shouldn't happen
762                    throw new java.io.StreamCorruptedException("Invalid name: "
763                            + unparsed);
764                }
765            }
766        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.