1 7 8 package javax.naming.ldap; 9 10 import java.util.Iterator ; 11 import java.util.NoSuchElementException ; 12 import java.util.ArrayList ; 13 import java.util.Collections ; 14 15 import javax.naming.InvalidNameException ; 16 import javax.naming.directory.BasicAttributes ; 17 import javax.naming.directory.Attributes ; 18 import javax.naming.directory.Attribute ; 19 import javax.naming.NamingEnumeration ; 20 import javax.naming.NamingException ; 21 22 import java.io.Serializable ; 23 import java.io.ObjectOutputStream ; 24 import java.io.ObjectInputStream ; 25 import java.io.IOException ; 26 27 87 88 public class Rdn implements Serializable , Comparable <Object > { 89 90 private transient ArrayList entries; 92 93 private static final int DEFAULT_SIZE = 1; 95 96 private static final long serialVersionUID = -5994465067210009656L; 97 98 112 public Rdn(Attributes attrSet) throws InvalidNameException { 113 if (attrSet.size() == 0) { 114 throw new InvalidNameException ("Attributes cannot be empty"); 115 } 116 entries = new ArrayList (attrSet.size()); 117 NamingEnumeration attrs = attrSet.getAll(); 118 try { 119 for (int nEntries = 0; attrs.hasMore(); nEntries++) { 120 RdnEntry entry = new RdnEntry(); 121 Attribute attr = (Attribute ) attrs.next(); 122 entry.type = attr.getID(); 123 entry.value = attr.get(); 124 entries.add(nEntries, entry); 125 } 126 } catch (NamingException e) { 127 InvalidNameException e2 = new InvalidNameException ( 128 e.getMessage()); 129 e2.initCause(e); 130 throw e2; 131 } 132 sort(); } 134 135 146 public Rdn(String rdnString) throws InvalidNameException { 147 entries = new ArrayList (DEFAULT_SIZE); 148 (new Rfc2253Parser (rdnString)).parseRdn(this); 149 } 150 151 157 public Rdn(Rdn rdn) { 158 entries = new ArrayList (rdn.entries.size()); 159 entries.addAll(rdn.entries); 160 } 161 162 176 public Rdn(String type, Object value) throws InvalidNameException { 177 if (value == null) { 178 throw new NullPointerException ("Cannot set value to null"); 179 } 180 if (type.equals("") || isEmptyValue(value)) { 181 throw new InvalidNameException ( 182 "type or value cannot be empty, type:" + type + 183 " value:" + value); 184 } 185 entries = new ArrayList (DEFAULT_SIZE); 186 put(type, value); 187 } 188 189 private boolean isEmptyValue(Object val) { 190 return ((val instanceof String ) && val.equals("")) || 191 ((val instanceof byte[]) && (((byte[]) val).length == 0)); 192 } 193 194 Rdn() { 196 entries = new ArrayList (DEFAULT_SIZE); 197 } 198 199 211 Rdn put(String type, Object value) { 212 213 RdnEntry newEntry = new RdnEntry(); 215 newEntry.type = type; 216 if (value instanceof byte[]) { newEntry.value = ((byte[]) value).clone(); 218 } else { 219 newEntry.value = value; 220 } 221 entries.add(newEntry); 222 return this; 223 } 224 225 void sort() { 226 if (entries.size() > 1) { 227 Collections.sort(entries); 228 } 229 } 230 231 242 public Object getValue() { 243 return ((RdnEntry) entries.get(0)).getValue(); 244 } 245 246 260 public String getType() { 261 return ((RdnEntry) entries.get(0)).getType(); 262 } 263 264 271 public String toString() { 272 StringBuilder builder = new StringBuilder (); 273 int size = entries.size(); 274 if (size > 0) { 275 builder.append(entries.get(0)); 276 } 277 for (int next = 1; next < size; next++) { 278 builder.append('+'); 279 builder.append(entries.get(next)); 280 } 281 return builder.toString(); 282 } 283 284 303 public int compareTo(Object obj) { 304 if (!(obj instanceof Rdn )) { 305 throw new ClassCastException ("The obj is not a Rdn"); 306 } 307 if (obj == this) { 308 return 0; 309 } 310 Rdn that = (Rdn ) obj; 311 int minSize = Math.min(entries.size(), that.entries.size()); 312 for (int i = 0; i < minSize; i++) { 313 314 int diff = ((RdnEntry) entries.get(i)).compareTo( 316 that.entries.get(i)); 317 if (diff != 0) { 318 return diff; 319 } 320 } 321 return (entries.size() - that.entries.size()); } 323 324 345 public boolean equals(Object obj) { 346 if (obj == this) { 347 return true; 348 } 349 if (!(obj instanceof Rdn )) { 350 return false; 351 } 352 Rdn that = (Rdn ) obj; 353 if (entries.size() != that.size()) { 354 return false; 355 } 356 for (int i = 0; i < entries.size(); i++) { 357 if (!entries.get(i).equals(that.entries.get(i))) { 358 return false; 359 } 360 } 361 return true; 362 } 363 364 372 public int hashCode() { 373 374 int hash = 0; 376 377 for (int i = 0; i < entries.size(); i++) { 379 hash += entries.get(i).hashCode(); 380 } 381 return hash; 382 } 383 384 391 public Attributes toAttributes() { 392 Attributes attrs = new BasicAttributes (true); 393 for (int i = 0; i < entries.size(); i++) { 394 RdnEntry entry = (RdnEntry) entries.get(i); 395 Attribute attr = attrs.put(entry.getType(), entry.getValue()); 396 if (attr != null) { 397 attr.add(entry.getValue()); 398 attrs.put(entry.getType(), attr); 399 } 400 } 401 return attrs; 402 } 403 404 405 private static class RdnEntry implements Comparable { 406 private String type; 407 private Object value; 408 409 private String comparable = null; 412 413 String getType() { 414 return type; 415 } 416 417 Object getValue() { 418 return value; 419 } 420 421 public int compareTo(Object obj) { 422 423 RdnEntry that = (RdnEntry) obj; 426 427 int diff = type.toUpperCase().compareTo( 428 that.type.toUpperCase()); 429 if (diff != 0) { 430 return diff; 431 } 432 if (value.equals(that.value)) { return 0; 434 } 435 return getValueComparable().compareTo( 436 that.getValueComparable()); 437 } 438 439 public boolean equals(Object obj) { 440 if (obj == this) { 441 return true; 442 } 443 if (!(obj instanceof RdnEntry)) { 444 return false; 445 } 446 447 RdnEntry that = (RdnEntry) obj; 449 return (type.equalsIgnoreCase(that.type)) && 450 (getValueComparable().equals( 451 that.getValueComparable())); 452 } 453 454 public int hashCode() { 455 return (type.toUpperCase().hashCode() + 456 getValueComparable().hashCode()); 457 } 458 459 public String toString() { 460 return type + "=" + escapeValue(value); 461 } 462 463 private String getValueComparable() { 464 if (comparable != null) { 465 return comparable; } 467 468 if (value instanceof byte[]) { 470 comparable = escapeBinaryValue((byte[]) value); 471 } else { 472 comparable = ((String ) value).toUpperCase(); 473 } 474 return comparable; 475 } 476 } 477 478 482 public int size() { 483 return entries.size(); 484 } 485 486 501 public static String escapeValue(Object val) { 502 return (val instanceof byte[]) 503 ? escapeBinaryValue((byte[])val) 504 : escapeStringValue((String )val); 505 } 506 507 514 private static final String escapees = ",=+<>#;\"\\"; 515 516 private static String escapeStringValue(String val) { 517 518 char[] chars = val.toCharArray(); 519 StringBuilder builder = new StringBuilder (2 * val.length()); 520 521 int lead; for (lead = 0; lead < chars.length; lead++) { 524 if (!isWhitespace(chars[lead])) { 525 break; 526 } 527 } 528 int trail; for (trail = chars.length - 1; trail >= 0; trail--) { 530 if (!isWhitespace(chars[trail])) { 531 break; 532 } 533 } 534 535 for (int i = 0; i < chars.length; i++) { 536 char c = chars[i]; 537 if ((i < lead) || (i > trail) || (escapees.indexOf(c) >= 0)) { 538 builder.append('\\'); 539 } 540 builder.append(c); 541 } 542 return builder.toString(); 543 } 544 545 551 private static String escapeBinaryValue(byte[] val) { 552 553 StringBuilder builder = new StringBuilder (1 + 2 * val.length); 554 builder.append("#"); 555 556 for (int i = 0; i < val.length; i++) { 557 byte b = val[i]; 558 builder.append(Character.forDigit(0xF & (b >>> 4), 16)); 559 builder.append(Character.forDigit(0xF & b, 16)); 560 } 561 return builder.toString(); 562 } 564 565 585 public static Object unescapeValue(String val) { 586 587 char[] chars = val.toCharArray(); 588 int beg = 0; 589 int end = chars.length; 590 591 while ((beg < end) && isWhitespace(chars[beg])) { 593 ++beg; 594 } 595 596 while ((beg < end) && isWhitespace(chars[end - 1])) { 597 --end; 598 } 599 600 if (end != chars.length && 604 (beg < end) && 605 chars[end - 1] == '\\') { 606 end++; 607 } 608 if (beg >= end) { 609 return ""; 610 } 611 612 if (chars[beg] == '#') { 613 return decodeHexPairs(chars, ++beg, end); 615 } 616 617 if ((chars[beg] == '\"') && (chars[end - 1] == '\"')) { 619 ++beg; 620 --end; 621 } 622 623 StringBuilder builder = new StringBuilder (end - beg); 624 int esc = -1; 626 for (int i = beg; i < end; i++) { 627 if ((chars[i] == '\\') && (i + 1 < end)) { 628 if (!Character.isLetterOrDigit(chars[i + 1])) { 629 ++i; builder.append(chars[i]); esc = i; 632 } else { 633 634 byte[] utf8 = getUtf8Octets(chars, i, end); 636 if (utf8.length > 0) { 637 try { 638 builder.append(new String (utf8, "UTF8")); 639 } catch (java.io.UnsupportedEncodingException e) { 640 } 642 i += utf8.length * 3 - 1; 643 } else { 645 throw new IllegalArgumentException ( 647 "Not a valid attribute string value:" + 648 val + ",improper usage of backslash"); 649 } 650 } 651 } else { 652 builder.append(chars[i]); } 654 } 655 656 int len = builder.length(); 659 if (isWhitespace(builder.charAt(len - 1)) && esc != (end - 1)) { 660 builder.setLength(len - 1); 661 } 662 return builder.toString(); 663 } 664 665 666 671 private static byte[] decodeHexPairs(char[] chars, int beg, int end) { 672 byte[] bytes = new byte[(end - beg) / 2]; 673 for (int i = 0; beg + 1 < end; i++) { 674 int hi = Character.digit(chars[beg], 16); 675 int lo = Character.digit(chars[beg + 1], 16); 676 if (hi < 0 || lo < 0) { 677 break; 678 } 679 bytes[i] = (byte)((hi<<4) + lo); 680 beg += 2; 681 } 682 if (beg != end) { 683 throw new IllegalArgumentException ( 684 "Illegal attribute value: " + new String (chars)); 685 } 686 return bytes; 687 } 688 689 697 private static byte[] getUtf8Octets(char[] chars, int beg, int end) { 698 byte[] utf8 = new byte[(end - beg) / 3]; int len = 0; 701 while ((beg + 2 < end) && 702 (chars[beg++] == '\\')) { 703 int hi = Character.digit(chars[beg++], 16); 704 int lo = Character.digit(chars[beg++], 16); 705 if (hi < 0 || lo < 0) { 706 break; 707 } 708 utf8[len++] = (byte)((hi<<4) + lo); 709 } 710 if (len == utf8.length) { 711 return utf8; 712 } else { 713 byte[] res = new byte[len]; 714 System.arraycopy(utf8, 0, res, 0, len); 715 return res; 716 } 717 } 718 719 722 private static boolean isWhitespace(char c) { 723 return (c == ' ' || c == '\r'); 724 } 725 726 732 private void writeObject(ObjectOutputStream s) 733 throws java.io.IOException { 734 s.defaultWriteObject(); 735 s.writeObject(toString()); 736 } 737 738 private void readObject(ObjectInputStream s) 739 throws IOException , ClassNotFoundException { 740 s.defaultReadObject(); 741 entries = new ArrayList (DEFAULT_SIZE); 742 String unparsed = (String ) s.readObject(); 743 try { 744 (new Rfc2253Parser (unparsed)).parseRdn(this); 745 } catch (InvalidNameException e) { 746 throw new java.io.StreamCorruptedException ( 748 "Invalid name: " + unparsed); 749 } 750 } 751 } 752 | Popular Tags |