001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS 026 */ 027package org.opends.server.util; 028 029import static org.opends.messages.UtilityMessages.*; 030import static org.opends.server.util.ServerConstants.*; 031 032import java.io.*; 033import java.lang.reflect.InvocationTargetException; 034import java.net.InetAddress; 035import java.net.InetSocketAddress; 036import java.net.ServerSocket; 037import java.net.Socket; 038import java.nio.ByteBuffer; 039import java.nio.channels.SelectionKey; 040import java.nio.channels.Selector; 041import java.nio.channels.SocketChannel; 042import java.text.ParseException; 043import java.text.SimpleDateFormat; 044import java.util.*; 045 046import javax.naming.InitialContext; 047import javax.naming.NamingException; 048 049import org.forgerock.i18n.LocalizableMessage; 050import org.forgerock.i18n.LocalizableMessageBuilder; 051import org.forgerock.i18n.LocalizableMessageDescriptor; 052import org.forgerock.i18n.slf4j.LocalizedLogger; 053import org.forgerock.opendj.ldap.ByteSequence; 054import org.forgerock.opendj.ldap.ByteString; 055import org.forgerock.util.Reject; 056import org.opends.messages.ToolMessages; 057import org.opends.server.api.ClientConnection; 058import org.opends.server.core.DirectoryServer; 059import org.opends.server.core.ServerContext; 060import org.opends.server.types.*; 061 062import com.forgerock.opendj.cli.Argument; 063import com.forgerock.opendj.cli.ArgumentException; 064 065/** 066 * This class defines a number of static utility methods that may be used 067 * throughout the server. Note that because of the frequency with which these 068 * methods are expected to be used, very little debug logging will be performed 069 * to prevent the log from filling up with unimportant calls and to reduce the 070 * impact that debugging may have on performance. 071 */ 072@org.opends.server.types.PublicAPI( 073 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED, 074 mayInstantiate=false, 075 mayExtend=false, 076 mayInvoke=true) 077public final class StaticUtils 078{ 079 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 080 081 /** The number of bytes of a Java int. A Java int is 32 bits, i.e. 4 bytes. */ 082 public static final int INT_SIZE = 4; 083 /** The number of bytes of a Java long. A Java int is 64 bits, i.e. 8 bytes. */ 084 public static final int LONG_SIZE = 8; 085 086 /** 087 * Number of bytes in a Kibibyte. 088 * <p> 089 * Example usage: 090 * <pre> 091 * int _10KB = 10 * KB; 092 * </pre> 093 */ 094 public static final int KB = 1024; 095 /** 096 * Number of bytes in a Mebibyte. 097 * <p> 098 * Example usage: 099 * <pre> 100 * int _10MB = 10 * MB; 101 * </pre> 102 */ 103 public static final int MB = KB * KB; 104 105 /** Private constructor to prevent instantiation. */ 106 private StaticUtils() { 107 // No implementation required. 108 } 109 110 111 112 /** 113 * Construct a byte array containing the UTF-8 encoding of the 114 * provided string. This is significantly faster 115 * than calling {@link String#getBytes(String)} for ASCII strings. 116 * 117 * @param s 118 * The string to convert to a UTF-8 byte array. 119 * @return Returns a byte array containing the UTF-8 encoding of the 120 * provided string. 121 */ 122 public static byte[] getBytes(String s) 123 { 124 if (s == null) 125 { 126 return null; 127 } 128 129 try 130 { 131 char c; 132 int length = s.length(); 133 byte[] returnArray = new byte[length]; 134 for (int i=0; i < length; i++) 135 { 136 c = s.charAt(i); 137 returnArray[i] = (byte) (c & 0x0000007F); 138 if (c != returnArray[i]) 139 { 140 return s.getBytes("UTF-8"); 141 } 142 } 143 144 return returnArray; 145 } 146 catch (Exception e) 147 { 148 logger.traceException(e); 149 150 try 151 { 152 return s.getBytes("UTF-8"); 153 } 154 catch (Exception e2) 155 { 156 logger.traceException(e2); 157 158 return s.getBytes(); 159 } 160 } 161 } 162 163 164 165 /** 166 * Returns the provided byte array decoded as a UTF-8 string without throwing 167 * an UnsupportedEncodingException. This method is equivalent to: 168 * 169 * <pre> 170 * try 171 * { 172 * return new String(bytes, "UTF-8"); 173 * } 174 * catch (UnsupportedEncodingException e) 175 * { 176 * // Should never happen: UTF-8 is always supported. 177 * throw new RuntimeException(e); 178 * } 179 * </pre> 180 * 181 * @param bytes 182 * The byte array to be decoded as a UTF-8 string. 183 * @return The decoded string. 184 */ 185 public static String decodeUTF8(final byte[] bytes) 186 { 187 Reject.ifNull(bytes); 188 189 if (bytes.length == 0) 190 { 191 return "".intern(); 192 } 193 194 final StringBuilder builder = new StringBuilder(bytes.length); 195 final int sz = bytes.length; 196 197 for (int i = 0; i < sz; i++) 198 { 199 final byte b = bytes[i]; 200 if ((b & 0x7f) != b) 201 { 202 try 203 { 204 builder.append(new String(bytes, i, (sz - i), "UTF-8")); 205 } 206 catch (UnsupportedEncodingException e) 207 { 208 // Should never happen: UTF-8 is always supported. 209 throw new RuntimeException(e); 210 } 211 break; 212 } 213 builder.append((char) b); 214 } 215 return builder.toString(); 216 } 217 218 219 220 /** 221 * Construct a byte array containing the UTF-8 encoding of the 222 * provided <code>char</code> array. 223 * 224 * @param chars 225 * The character array to convert to a UTF-8 byte array. 226 * @return Returns a byte array containing the UTF-8 encoding of the 227 * provided <code>char</code> array. 228 */ 229 public static byte[] getBytes(char[] chars) 230 { 231 return getBytes(new String(chars)); 232 } 233 234 235 236 /** 237 * Retrieves a string representation of the provided byte in hexadecimal. 238 * 239 * @param b The byte for which to retrieve the hexadecimal string 240 * representation. 241 * 242 * @return The string representation of the provided byte in hexadecimal. 243 */ 244 public static String byteToHex(byte b) 245 { 246 switch (b & 0xFF) 247 { 248 case 0x00: return "00"; 249 case 0x01: return "01"; 250 case 0x02: return "02"; 251 case 0x03: return "03"; 252 case 0x04: return "04"; 253 case 0x05: return "05"; 254 case 0x06: return "06"; 255 case 0x07: return "07"; 256 case 0x08: return "08"; 257 case 0x09: return "09"; 258 case 0x0A: return "0A"; 259 case 0x0B: return "0B"; 260 case 0x0C: return "0C"; 261 case 0x0D: return "0D"; 262 case 0x0E: return "0E"; 263 case 0x0F: return "0F"; 264 case 0x10: return "10"; 265 case 0x11: return "11"; 266 case 0x12: return "12"; 267 case 0x13: return "13"; 268 case 0x14: return "14"; 269 case 0x15: return "15"; 270 case 0x16: return "16"; 271 case 0x17: return "17"; 272 case 0x18: return "18"; 273 case 0x19: return "19"; 274 case 0x1A: return "1A"; 275 case 0x1B: return "1B"; 276 case 0x1C: return "1C"; 277 case 0x1D: return "1D"; 278 case 0x1E: return "1E"; 279 case 0x1F: return "1F"; 280 case 0x20: return "20"; 281 case 0x21: return "21"; 282 case 0x22: return "22"; 283 case 0x23: return "23"; 284 case 0x24: return "24"; 285 case 0x25: return "25"; 286 case 0x26: return "26"; 287 case 0x27: return "27"; 288 case 0x28: return "28"; 289 case 0x29: return "29"; 290 case 0x2A: return "2A"; 291 case 0x2B: return "2B"; 292 case 0x2C: return "2C"; 293 case 0x2D: return "2D"; 294 case 0x2E: return "2E"; 295 case 0x2F: return "2F"; 296 case 0x30: return "30"; 297 case 0x31: return "31"; 298 case 0x32: return "32"; 299 case 0x33: return "33"; 300 case 0x34: return "34"; 301 case 0x35: return "35"; 302 case 0x36: return "36"; 303 case 0x37: return "37"; 304 case 0x38: return "38"; 305 case 0x39: return "39"; 306 case 0x3A: return "3A"; 307 case 0x3B: return "3B"; 308 case 0x3C: return "3C"; 309 case 0x3D: return "3D"; 310 case 0x3E: return "3E"; 311 case 0x3F: return "3F"; 312 case 0x40: return "40"; 313 case 0x41: return "41"; 314 case 0x42: return "42"; 315 case 0x43: return "43"; 316 case 0x44: return "44"; 317 case 0x45: return "45"; 318 case 0x46: return "46"; 319 case 0x47: return "47"; 320 case 0x48: return "48"; 321 case 0x49: return "49"; 322 case 0x4A: return "4A"; 323 case 0x4B: return "4B"; 324 case 0x4C: return "4C"; 325 case 0x4D: return "4D"; 326 case 0x4E: return "4E"; 327 case 0x4F: return "4F"; 328 case 0x50: return "50"; 329 case 0x51: return "51"; 330 case 0x52: return "52"; 331 case 0x53: return "53"; 332 case 0x54: return "54"; 333 case 0x55: return "55"; 334 case 0x56: return "56"; 335 case 0x57: return "57"; 336 case 0x58: return "58"; 337 case 0x59: return "59"; 338 case 0x5A: return "5A"; 339 case 0x5B: return "5B"; 340 case 0x5C: return "5C"; 341 case 0x5D: return "5D"; 342 case 0x5E: return "5E"; 343 case 0x5F: return "5F"; 344 case 0x60: return "60"; 345 case 0x61: return "61"; 346 case 0x62: return "62"; 347 case 0x63: return "63"; 348 case 0x64: return "64"; 349 case 0x65: return "65"; 350 case 0x66: return "66"; 351 case 0x67: return "67"; 352 case 0x68: return "68"; 353 case 0x69: return "69"; 354 case 0x6A: return "6A"; 355 case 0x6B: return "6B"; 356 case 0x6C: return "6C"; 357 case 0x6D: return "6D"; 358 case 0x6E: return "6E"; 359 case 0x6F: return "6F"; 360 case 0x70: return "70"; 361 case 0x71: return "71"; 362 case 0x72: return "72"; 363 case 0x73: return "73"; 364 case 0x74: return "74"; 365 case 0x75: return "75"; 366 case 0x76: return "76"; 367 case 0x77: return "77"; 368 case 0x78: return "78"; 369 case 0x79: return "79"; 370 case 0x7A: return "7A"; 371 case 0x7B: return "7B"; 372 case 0x7C: return "7C"; 373 case 0x7D: return "7D"; 374 case 0x7E: return "7E"; 375 case 0x7F: return "7F"; 376 case 0x80: return "80"; 377 case 0x81: return "81"; 378 case 0x82: return "82"; 379 case 0x83: return "83"; 380 case 0x84: return "84"; 381 case 0x85: return "85"; 382 case 0x86: return "86"; 383 case 0x87: return "87"; 384 case 0x88: return "88"; 385 case 0x89: return "89"; 386 case 0x8A: return "8A"; 387 case 0x8B: return "8B"; 388 case 0x8C: return "8C"; 389 case 0x8D: return "8D"; 390 case 0x8E: return "8E"; 391 case 0x8F: return "8F"; 392 case 0x90: return "90"; 393 case 0x91: return "91"; 394 case 0x92: return "92"; 395 case 0x93: return "93"; 396 case 0x94: return "94"; 397 case 0x95: return "95"; 398 case 0x96: return "96"; 399 case 0x97: return "97"; 400 case 0x98: return "98"; 401 case 0x99: return "99"; 402 case 0x9A: return "9A"; 403 case 0x9B: return "9B"; 404 case 0x9C: return "9C"; 405 case 0x9D: return "9D"; 406 case 0x9E: return "9E"; 407 case 0x9F: return "9F"; 408 case 0xA0: return "A0"; 409 case 0xA1: return "A1"; 410 case 0xA2: return "A2"; 411 case 0xA3: return "A3"; 412 case 0xA4: return "A4"; 413 case 0xA5: return "A5"; 414 case 0xA6: return "A6"; 415 case 0xA7: return "A7"; 416 case 0xA8: return "A8"; 417 case 0xA9: return "A9"; 418 case 0xAA: return "AA"; 419 case 0xAB: return "AB"; 420 case 0xAC: return "AC"; 421 case 0xAD: return "AD"; 422 case 0xAE: return "AE"; 423 case 0xAF: return "AF"; 424 case 0xB0: return "B0"; 425 case 0xB1: return "B1"; 426 case 0xB2: return "B2"; 427 case 0xB3: return "B3"; 428 case 0xB4: return "B4"; 429 case 0xB5: return "B5"; 430 case 0xB6: return "B6"; 431 case 0xB7: return "B7"; 432 case 0xB8: return "B8"; 433 case 0xB9: return "B9"; 434 case 0xBA: return "BA"; 435 case 0xBB: return "BB"; 436 case 0xBC: return "BC"; 437 case 0xBD: return "BD"; 438 case 0xBE: return "BE"; 439 case 0xBF: return "BF"; 440 case 0xC0: return "C0"; 441 case 0xC1: return "C1"; 442 case 0xC2: return "C2"; 443 case 0xC3: return "C3"; 444 case 0xC4: return "C4"; 445 case 0xC5: return "C5"; 446 case 0xC6: return "C6"; 447 case 0xC7: return "C7"; 448 case 0xC8: return "C8"; 449 case 0xC9: return "C9"; 450 case 0xCA: return "CA"; 451 case 0xCB: return "CB"; 452 case 0xCC: return "CC"; 453 case 0xCD: return "CD"; 454 case 0xCE: return "CE"; 455 case 0xCF: return "CF"; 456 case 0xD0: return "D0"; 457 case 0xD1: return "D1"; 458 case 0xD2: return "D2"; 459 case 0xD3: return "D3"; 460 case 0xD4: return "D4"; 461 case 0xD5: return "D5"; 462 case 0xD6: return "D6"; 463 case 0xD7: return "D7"; 464 case 0xD8: return "D8"; 465 case 0xD9: return "D9"; 466 case 0xDA: return "DA"; 467 case 0xDB: return "DB"; 468 case 0xDC: return "DC"; 469 case 0xDD: return "DD"; 470 case 0xDE: return "DE"; 471 case 0xDF: return "DF"; 472 case 0xE0: return "E0"; 473 case 0xE1: return "E1"; 474 case 0xE2: return "E2"; 475 case 0xE3: return "E3"; 476 case 0xE4: return "E4"; 477 case 0xE5: return "E5"; 478 case 0xE6: return "E6"; 479 case 0xE7: return "E7"; 480 case 0xE8: return "E8"; 481 case 0xE9: return "E9"; 482 case 0xEA: return "EA"; 483 case 0xEB: return "EB"; 484 case 0xEC: return "EC"; 485 case 0xED: return "ED"; 486 case 0xEE: return "EE"; 487 case 0xEF: return "EF"; 488 case 0xF0: return "F0"; 489 case 0xF1: return "F1"; 490 case 0xF2: return "F2"; 491 case 0xF3: return "F3"; 492 case 0xF4: return "F4"; 493 case 0xF5: return "F5"; 494 case 0xF6: return "F6"; 495 case 0xF7: return "F7"; 496 case 0xF8: return "F8"; 497 case 0xF9: return "F9"; 498 case 0xFA: return "FA"; 499 case 0xFB: return "FB"; 500 case 0xFC: return "FC"; 501 case 0xFD: return "FD"; 502 case 0xFE: return "FE"; 503 case 0xFF: return "FF"; 504 default: return "??"; 505 } 506 } 507 508 509 510 /** 511 * Retrieves a string representation of the provided byte in hexadecimal. 512 * 513 * @param b The byte for which to retrieve the hexadecimal string 514 * representation. 515 * 516 * @return The string representation of the provided byte in hexadecimal 517 * using lowercase characters. 518 */ 519 public static String byteToLowerHex(byte b) 520 { 521 switch (b & 0xFF) 522 { 523 case 0x00: return "00"; 524 case 0x01: return "01"; 525 case 0x02: return "02"; 526 case 0x03: return "03"; 527 case 0x04: return "04"; 528 case 0x05: return "05"; 529 case 0x06: return "06"; 530 case 0x07: return "07"; 531 case 0x08: return "08"; 532 case 0x09: return "09"; 533 case 0x0A: return "0a"; 534 case 0x0B: return "0b"; 535 case 0x0C: return "0c"; 536 case 0x0D: return "0d"; 537 case 0x0E: return "0e"; 538 case 0x0F: return "0f"; 539 case 0x10: return "10"; 540 case 0x11: return "11"; 541 case 0x12: return "12"; 542 case 0x13: return "13"; 543 case 0x14: return "14"; 544 case 0x15: return "15"; 545 case 0x16: return "16"; 546 case 0x17: return "17"; 547 case 0x18: return "18"; 548 case 0x19: return "19"; 549 case 0x1A: return "1a"; 550 case 0x1B: return "1b"; 551 case 0x1C: return "1c"; 552 case 0x1D: return "1d"; 553 case 0x1E: return "1e"; 554 case 0x1F: return "1f"; 555 case 0x20: return "20"; 556 case 0x21: return "21"; 557 case 0x22: return "22"; 558 case 0x23: return "23"; 559 case 0x24: return "24"; 560 case 0x25: return "25"; 561 case 0x26: return "26"; 562 case 0x27: return "27"; 563 case 0x28: return "28"; 564 case 0x29: return "29"; 565 case 0x2A: return "2a"; 566 case 0x2B: return "2b"; 567 case 0x2C: return "2c"; 568 case 0x2D: return "2d"; 569 case 0x2E: return "2e"; 570 case 0x2F: return "2f"; 571 case 0x30: return "30"; 572 case 0x31: return "31"; 573 case 0x32: return "32"; 574 case 0x33: return "33"; 575 case 0x34: return "34"; 576 case 0x35: return "35"; 577 case 0x36: return "36"; 578 case 0x37: return "37"; 579 case 0x38: return "38"; 580 case 0x39: return "39"; 581 case 0x3A: return "3a"; 582 case 0x3B: return "3b"; 583 case 0x3C: return "3c"; 584 case 0x3D: return "3d"; 585 case 0x3E: return "3e"; 586 case 0x3F: return "3f"; 587 case 0x40: return "40"; 588 case 0x41: return "41"; 589 case 0x42: return "42"; 590 case 0x43: return "43"; 591 case 0x44: return "44"; 592 case 0x45: return "45"; 593 case 0x46: return "46"; 594 case 0x47: return "47"; 595 case 0x48: return "48"; 596 case 0x49: return "49"; 597 case 0x4A: return "4a"; 598 case 0x4B: return "4b"; 599 case 0x4C: return "4c"; 600 case 0x4D: return "4d"; 601 case 0x4E: return "4e"; 602 case 0x4F: return "4f"; 603 case 0x50: return "50"; 604 case 0x51: return "51"; 605 case 0x52: return "52"; 606 case 0x53: return "53"; 607 case 0x54: return "54"; 608 case 0x55: return "55"; 609 case 0x56: return "56"; 610 case 0x57: return "57"; 611 case 0x58: return "58"; 612 case 0x59: return "59"; 613 case 0x5A: return "5a"; 614 case 0x5B: return "5b"; 615 case 0x5C: return "5c"; 616 case 0x5D: return "5d"; 617 case 0x5E: return "5e"; 618 case 0x5F: return "5f"; 619 case 0x60: return "60"; 620 case 0x61: return "61"; 621 case 0x62: return "62"; 622 case 0x63: return "63"; 623 case 0x64: return "64"; 624 case 0x65: return "65"; 625 case 0x66: return "66"; 626 case 0x67: return "67"; 627 case 0x68: return "68"; 628 case 0x69: return "69"; 629 case 0x6A: return "6a"; 630 case 0x6B: return "6b"; 631 case 0x6C: return "6c"; 632 case 0x6D: return "6d"; 633 case 0x6E: return "6e"; 634 case 0x6F: return "6f"; 635 case 0x70: return "70"; 636 case 0x71: return "71"; 637 case 0x72: return "72"; 638 case 0x73: return "73"; 639 case 0x74: return "74"; 640 case 0x75: return "75"; 641 case 0x76: return "76"; 642 case 0x77: return "77"; 643 case 0x78: return "78"; 644 case 0x79: return "79"; 645 case 0x7A: return "7a"; 646 case 0x7B: return "7b"; 647 case 0x7C: return "7c"; 648 case 0x7D: return "7d"; 649 case 0x7E: return "7e"; 650 case 0x7F: return "7f"; 651 case 0x80: return "80"; 652 case 0x81: return "81"; 653 case 0x82: return "82"; 654 case 0x83: return "83"; 655 case 0x84: return "84"; 656 case 0x85: return "85"; 657 case 0x86: return "86"; 658 case 0x87: return "87"; 659 case 0x88: return "88"; 660 case 0x89: return "89"; 661 case 0x8A: return "8a"; 662 case 0x8B: return "8b"; 663 case 0x8C: return "8c"; 664 case 0x8D: return "8d"; 665 case 0x8E: return "8e"; 666 case 0x8F: return "8f"; 667 case 0x90: return "90"; 668 case 0x91: return "91"; 669 case 0x92: return "92"; 670 case 0x93: return "93"; 671 case 0x94: return "94"; 672 case 0x95: return "95"; 673 case 0x96: return "96"; 674 case 0x97: return "97"; 675 case 0x98: return "98"; 676 case 0x99: return "99"; 677 case 0x9A: return "9a"; 678 case 0x9B: return "9b"; 679 case 0x9C: return "9c"; 680 case 0x9D: return "9d"; 681 case 0x9E: return "9e"; 682 case 0x9F: return "9f"; 683 case 0xA0: return "a0"; 684 case 0xA1: return "a1"; 685 case 0xA2: return "a2"; 686 case 0xA3: return "a3"; 687 case 0xA4: return "a4"; 688 case 0xA5: return "a5"; 689 case 0xA6: return "a6"; 690 case 0xA7: return "a7"; 691 case 0xA8: return "a8"; 692 case 0xA9: return "a9"; 693 case 0xAA: return "aa"; 694 case 0xAB: return "ab"; 695 case 0xAC: return "ac"; 696 case 0xAD: return "ad"; 697 case 0xAE: return "ae"; 698 case 0xAF: return "af"; 699 case 0xB0: return "b0"; 700 case 0xB1: return "b1"; 701 case 0xB2: return "b2"; 702 case 0xB3: return "b3"; 703 case 0xB4: return "b4"; 704 case 0xB5: return "b5"; 705 case 0xB6: return "b6"; 706 case 0xB7: return "b7"; 707 case 0xB8: return "b8"; 708 case 0xB9: return "b9"; 709 case 0xBA: return "ba"; 710 case 0xBB: return "bb"; 711 case 0xBC: return "bc"; 712 case 0xBD: return "bd"; 713 case 0xBE: return "be"; 714 case 0xBF: return "bf"; 715 case 0xC0: return "c0"; 716 case 0xC1: return "c1"; 717 case 0xC2: return "c2"; 718 case 0xC3: return "c3"; 719 case 0xC4: return "c4"; 720 case 0xC5: return "c5"; 721 case 0xC6: return "c6"; 722 case 0xC7: return "c7"; 723 case 0xC8: return "c8"; 724 case 0xC9: return "c9"; 725 case 0xCA: return "ca"; 726 case 0xCB: return "cb"; 727 case 0xCC: return "cc"; 728 case 0xCD: return "cd"; 729 case 0xCE: return "ce"; 730 case 0xCF: return "cf"; 731 case 0xD0: return "d0"; 732 case 0xD1: return "d1"; 733 case 0xD2: return "d2"; 734 case 0xD3: return "d3"; 735 case 0xD4: return "d4"; 736 case 0xD5: return "d5"; 737 case 0xD6: return "d6"; 738 case 0xD7: return "d7"; 739 case 0xD8: return "d8"; 740 case 0xD9: return "d9"; 741 case 0xDA: return "da"; 742 case 0xDB: return "db"; 743 case 0xDC: return "dc"; 744 case 0xDD: return "dd"; 745 case 0xDE: return "de"; 746 case 0xDF: return "df"; 747 case 0xE0: return "e0"; 748 case 0xE1: return "e1"; 749 case 0xE2: return "e2"; 750 case 0xE3: return "e3"; 751 case 0xE4: return "e4"; 752 case 0xE5: return "e5"; 753 case 0xE6: return "e6"; 754 case 0xE7: return "e7"; 755 case 0xE8: return "e8"; 756 case 0xE9: return "e9"; 757 case 0xEA: return "ea"; 758 case 0xEB: return "eb"; 759 case 0xEC: return "ec"; 760 case 0xED: return "ed"; 761 case 0xEE: return "ee"; 762 case 0xEF: return "ef"; 763 case 0xF0: return "f0"; 764 case 0xF1: return "f1"; 765 case 0xF2: return "f2"; 766 case 0xF3: return "f3"; 767 case 0xF4: return "f4"; 768 case 0xF5: return "f5"; 769 case 0xF6: return "f6"; 770 case 0xF7: return "f7"; 771 case 0xF8: return "f8"; 772 case 0xF9: return "f9"; 773 case 0xFA: return "fa"; 774 case 0xFB: return "fb"; 775 case 0xFC: return "fc"; 776 case 0xFD: return "fd"; 777 case 0xFE: return "fe"; 778 case 0xFF: return "ff"; 779 default: return "??"; 780 } 781 } 782 783 784 785 /** 786 * Retrieves the printable ASCII representation of the provided byte. 787 * 788 * @param b The byte for which to retrieve the printable ASCII 789 * representation. 790 * 791 * @return The printable ASCII representation of the provided byte, or a 792 * space if the provided byte does not have printable ASCII 793 * representation. 794 */ 795 public static char byteToASCII(byte b) 796 { 797 if (32 <= b && b <= 126) 798 { 799 return (char) b; 800 } 801 return ' '; 802 } 803 804 805 806 /** 807 * Retrieves a string representation of the contents of the provided byte 808 * array using hexadecimal characters with no space between each byte. 809 * 810 * @param b The byte array containing the data. 811 * 812 * @return A string representation of the contents of the provided byte 813 * array using hexadecimal characters. 814 */ 815 public static String bytesToHexNoSpace(byte[] b) 816 { 817 if (b == null || b.length == 0) 818 { 819 return ""; 820 } 821 822 int arrayLength = b.length; 823 StringBuilder buffer = new StringBuilder(arrayLength * 2); 824 825 for (int i=0; i < arrayLength; i++) 826 { 827 buffer.append(byteToHex(b[i])); 828 } 829 830 return buffer.toString(); 831 } 832 833 834 835 /** 836 * Retrieves a string representation of the contents of the provided byte 837 * array using hexadecimal characters and a space between each byte. 838 * 839 * @param b The byte array containing the data. 840 * @return A string representation of the contents of the provided byte 841 * array using hexadecimal characters. 842 */ 843 public static String bytesToHex(byte[] b) 844 { 845 if (b == null || b.length == 0) 846 { 847 return ""; 848 } 849 850 int arrayLength = b.length; 851 StringBuilder buffer = new StringBuilder((arrayLength - 1) * 3 + 2); 852 buffer.append(byteToHex(b[0])); 853 854 for (int i=1; i < arrayLength; i++) 855 { 856 buffer.append(" "); 857 buffer.append(byteToHex(b[i])); 858 } 859 860 return buffer.toString(); 861 } 862 863 /** 864 * Retrieves a string representation of the contents of the provided byte 865 * sequence using hexadecimal characters and a space between each byte. 866 * 867 * @param b The byte sequence containing the data. 868 * @return A string representation of the contents of the provided byte 869 * sequence using hexadecimal characters. 870 */ 871 public static String bytesToHex(ByteSequence b) 872 { 873 if (b == null || b.length() == 0) 874 { 875 return ""; 876 } 877 878 int arrayLength = b.length(); 879 StringBuilder buffer = new StringBuilder((arrayLength - 1) * 3 + 2); 880 buffer.append(byteToHex(b.byteAt(0))); 881 882 for (int i=1; i < arrayLength; i++) 883 { 884 buffer.append(" "); 885 buffer.append(byteToHex(b.byteAt(i))); 886 } 887 888 return buffer.toString(); 889 } 890 891 892 893 /** 894 * Retrieves a string representation of the contents of the provided byte 895 * array using hexadecimal characters and a colon between each byte. 896 * 897 * @param b The byte array containing the data. 898 * 899 * @return A string representation of the contents of the provided byte 900 * array using hexadecimal characters. 901 */ 902 public static String bytesToColonDelimitedHex(byte[] b) 903 { 904 if (b == null || b.length == 0) 905 { 906 return ""; 907 } 908 909 int arrayLength = b.length; 910 StringBuilder buffer = new StringBuilder((arrayLength - 1) * 3 + 2); 911 buffer.append(byteToHex(b[0])); 912 913 for (int i=1; i < arrayLength; i++) 914 { 915 buffer.append(":"); 916 buffer.append(byteToHex(b[i])); 917 } 918 919 return buffer.toString(); 920 } 921 922 923 924 /** 925 * Retrieves a string representation of the contents of the provided byte 926 * buffer using hexadecimal characters and a space between each byte. 927 * 928 * @param b The byte buffer containing the data. 929 * 930 * @return A string representation of the contents of the provided byte 931 * buffer using hexadecimal characters. 932 */ 933 public static String bytesToHex(ByteBuffer b) 934 { 935 if (b == null) 936 { 937 return ""; 938 } 939 940 int position = b.position(); 941 int limit = b.limit(); 942 int length = limit - position; 943 944 if (length == 0) 945 { 946 return ""; 947 } 948 949 StringBuilder buffer = new StringBuilder((length - 1) * 3 + 2); 950 buffer.append(byteToHex(b.get())); 951 952 for (int i=1; i < length; i++) 953 { 954 buffer.append(" "); 955 buffer.append(byteToHex(b.get())); 956 } 957 958 b.position(position); 959 b.limit(limit); 960 961 return buffer.toString(); 962 } 963 964 965 966 /** 967 * Appends a string representation of the provided byte array to the given 968 * buffer using the specified indent. The data will be formatted with sixteen 969 * hex bytes in a row followed by the ASCII representation, then wrapping to a 970 * new line as necessary. 971 * 972 * @param buffer The buffer to which the information is to be appended. 973 * @param b The byte array containing the data to write. 974 * @param indent The number of spaces to indent the output. 975 */ 976 public static void byteArrayToHexPlusAscii(StringBuilder buffer, byte[] b, 977 int indent) 978 { 979 StringBuilder indentBuf = new StringBuilder(indent); 980 for (int i=0 ; i < indent; i++) 981 { 982 indentBuf.append(' '); 983 } 984 985 986 987 int length = b.length; 988 int pos = 0; 989 while (length - pos >= 16) 990 { 991 StringBuilder asciiBuf = new StringBuilder(17); 992 993 buffer.append(indentBuf); 994 buffer.append(byteToHex(b[pos])); 995 asciiBuf.append(byteToASCII(b[pos])); 996 pos++; 997 998 for (int i=1; i < 16; i++, pos++) 999 { 1000 buffer.append(' '); 1001 buffer.append(byteToHex(b[pos])); 1002 asciiBuf.append(byteToASCII(b[pos])); 1003 1004 if (i == 7) 1005 { 1006 buffer.append(" "); 1007 asciiBuf.append(' '); 1008 } 1009 } 1010 1011 buffer.append(" "); 1012 buffer.append(asciiBuf); 1013 buffer.append(EOL); 1014 } 1015 1016 1017 int remaining = length - pos; 1018 if (remaining > 0) 1019 { 1020 StringBuilder asciiBuf = new StringBuilder(remaining+1); 1021 1022 buffer.append(indentBuf); 1023 buffer.append(byteToHex(b[pos])); 1024 asciiBuf.append(byteToASCII(b[pos])); 1025 pos++; 1026 1027 for (int i=1; i < 16; i++) 1028 { 1029 buffer.append(' '); 1030 1031 if (i < remaining) 1032 { 1033 buffer.append(byteToHex(b[pos])); 1034 asciiBuf.append(byteToASCII(b[pos])); 1035 pos++; 1036 } 1037 else 1038 { 1039 buffer.append(" "); 1040 } 1041 1042 if (i == 7) 1043 { 1044 buffer.append(" "); 1045 1046 if (i < remaining) 1047 { 1048 asciiBuf.append(' '); 1049 } 1050 } 1051 } 1052 1053 buffer.append(" "); 1054 buffer.append(asciiBuf); 1055 buffer.append(EOL); 1056 } 1057 } 1058 1059 1060 1061 /** 1062 * Appends a string representation of the remaining unread data in the 1063 * provided byte buffer to the given buffer using the specified indent. 1064 * The data will be formatted with sixteen hex bytes in a row followed by 1065 * the ASCII representation, then wrapping to a new line as necessary. 1066 * The state of the byte buffer is not changed. 1067 * 1068 * @param buffer The buffer to which the information is to be appended. 1069 * @param b The byte buffer containing the data to write. 1070 * The data from the position to the limit is written. 1071 * @param indent The number of spaces to indent the output. 1072 */ 1073 public static void byteArrayToHexPlusAscii(StringBuilder buffer, ByteBuffer b, 1074 int indent) 1075 { 1076 StringBuilder indentBuf = new StringBuilder(indent); 1077 for (int i=0 ; i < indent; i++) 1078 { 1079 indentBuf.append(' '); 1080 } 1081 1082 1083 int position = b.position(); 1084 int limit = b.limit(); 1085 int length = limit - position; 1086 int pos = 0; 1087 while (length - pos >= 16) 1088 { 1089 StringBuilder asciiBuf = new StringBuilder(17); 1090 1091 byte currentByte = b.get(); 1092 buffer.append(indentBuf); 1093 buffer.append(byteToHex(currentByte)); 1094 asciiBuf.append(byteToASCII(currentByte)); 1095 pos++; 1096 1097 for (int i=1; i < 16; i++, pos++) 1098 { 1099 currentByte = b.get(); 1100 buffer.append(' '); 1101 buffer.append(byteToHex(currentByte)); 1102 asciiBuf.append(byteToASCII(currentByte)); 1103 1104 if (i == 7) 1105 { 1106 buffer.append(" "); 1107 asciiBuf.append(' '); 1108 } 1109 } 1110 1111 buffer.append(" "); 1112 buffer.append(asciiBuf); 1113 buffer.append(EOL); 1114 } 1115 1116 1117 int remaining = length - pos; 1118 if (remaining > 0) 1119 { 1120 StringBuilder asciiBuf = new StringBuilder(remaining+1); 1121 1122 byte currentByte = b.get(); 1123 buffer.append(indentBuf); 1124 buffer.append(byteToHex(currentByte)); 1125 asciiBuf.append(byteToASCII(currentByte)); 1126 1127 for (int i=1; i < 16; i++) 1128 { 1129 buffer.append(' '); 1130 1131 if (i < remaining) 1132 { 1133 currentByte = b.get(); 1134 buffer.append(byteToHex(currentByte)); 1135 asciiBuf.append(byteToASCII(currentByte)); 1136 } 1137 else 1138 { 1139 buffer.append(" "); 1140 } 1141 1142 if (i == 7) 1143 { 1144 buffer.append(" "); 1145 1146 if (i < remaining) 1147 { 1148 asciiBuf.append(' '); 1149 } 1150 } 1151 } 1152 1153 buffer.append(" "); 1154 buffer.append(asciiBuf); 1155 buffer.append(EOL); 1156 } 1157 1158 b.position(position); 1159 b.limit(limit); 1160 } 1161 1162 1163 1164 /** 1165 * Retrieves a binary representation of the provided byte. It will always be 1166 * a sequence of eight zeros and/or ones. 1167 * 1168 * @param b The byte for which to retrieve the binary representation. 1169 * 1170 * @return The binary representation for the provided byte. 1171 */ 1172 public static String byteToBinary(byte b) 1173 { 1174 switch (b & 0xFF) 1175 { 1176 case 0x00: return "00000000"; 1177 case 0x01: return "00000001"; 1178 case 0x02: return "00000010"; 1179 case 0x03: return "00000011"; 1180 case 0x04: return "00000100"; 1181 case 0x05: return "00000101"; 1182 case 0x06: return "00000110"; 1183 case 0x07: return "00000111"; 1184 case 0x08: return "00001000"; 1185 case 0x09: return "00001001"; 1186 case 0x0A: return "00001010"; 1187 case 0x0B: return "00001011"; 1188 case 0x0C: return "00001100"; 1189 case 0x0D: return "00001101"; 1190 case 0x0E: return "00001110"; 1191 case 0x0F: return "00001111"; 1192 case 0x10: return "00010000"; 1193 case 0x11: return "00010001"; 1194 case 0x12: return "00010010"; 1195 case 0x13: return "00010011"; 1196 case 0x14: return "00010100"; 1197 case 0x15: return "00010101"; 1198 case 0x16: return "00010110"; 1199 case 0x17: return "00010111"; 1200 case 0x18: return "00011000"; 1201 case 0x19: return "00011001"; 1202 case 0x1A: return "00011010"; 1203 case 0x1B: return "00011011"; 1204 case 0x1C: return "00011100"; 1205 case 0x1D: return "00011101"; 1206 case 0x1E: return "00011110"; 1207 case 0x1F: return "00011111"; 1208 case 0x20: return "00100000"; 1209 case 0x21: return "00100001"; 1210 case 0x22: return "00100010"; 1211 case 0x23: return "00100011"; 1212 case 0x24: return "00100100"; 1213 case 0x25: return "00100101"; 1214 case 0x26: return "00100110"; 1215 case 0x27: return "00100111"; 1216 case 0x28: return "00101000"; 1217 case 0x29: return "00101001"; 1218 case 0x2A: return "00101010"; 1219 case 0x2B: return "00101011"; 1220 case 0x2C: return "00101100"; 1221 case 0x2D: return "00101101"; 1222 case 0x2E: return "00101110"; 1223 case 0x2F: return "00101111"; 1224 case 0x30: return "00110000"; 1225 case 0x31: return "00110001"; 1226 case 0x32: return "00110010"; 1227 case 0x33: return "00110011"; 1228 case 0x34: return "00110100"; 1229 case 0x35: return "00110101"; 1230 case 0x36: return "00110110"; 1231 case 0x37: return "00110111"; 1232 case 0x38: return "00111000"; 1233 case 0x39: return "00111001"; 1234 case 0x3A: return "00111010"; 1235 case 0x3B: return "00111011"; 1236 case 0x3C: return "00111100"; 1237 case 0x3D: return "00111101"; 1238 case 0x3E: return "00111110"; 1239 case 0x3F: return "00111111"; 1240 case 0x40: return "01000000"; 1241 case 0x41: return "01000001"; 1242 case 0x42: return "01000010"; 1243 case 0x43: return "01000011"; 1244 case 0x44: return "01000100"; 1245 case 0x45: return "01000101"; 1246 case 0x46: return "01000110"; 1247 case 0x47: return "01000111"; 1248 case 0x48: return "01001000"; 1249 case 0x49: return "01001001"; 1250 case 0x4A: return "01001010"; 1251 case 0x4B: return "01001011"; 1252 case 0x4C: return "01001100"; 1253 case 0x4D: return "01001101"; 1254 case 0x4E: return "01001110"; 1255 case 0x4F: return "01001111"; 1256 case 0x50: return "01010000"; 1257 case 0x51: return "01010001"; 1258 case 0x52: return "01010010"; 1259 case 0x53: return "01010011"; 1260 case 0x54: return "01010100"; 1261 case 0x55: return "01010101"; 1262 case 0x56: return "01010110"; 1263 case 0x57: return "01010111"; 1264 case 0x58: return "01011000"; 1265 case 0x59: return "01011001"; 1266 case 0x5A: return "01011010"; 1267 case 0x5B: return "01011011"; 1268 case 0x5C: return "01011100"; 1269 case 0x5D: return "01011101"; 1270 case 0x5E: return "01011110"; 1271 case 0x5F: return "01011111"; 1272 case 0x60: return "01100000"; 1273 case 0x61: return "01100001"; 1274 case 0x62: return "01100010"; 1275 case 0x63: return "01100011"; 1276 case 0x64: return "01100100"; 1277 case 0x65: return "01100101"; 1278 case 0x66: return "01100110"; 1279 case 0x67: return "01100111"; 1280 case 0x68: return "01101000"; 1281 case 0x69: return "01101001"; 1282 case 0x6A: return "01101010"; 1283 case 0x6B: return "01101011"; 1284 case 0x6C: return "01101100"; 1285 case 0x6D: return "01101101"; 1286 case 0x6E: return "01101110"; 1287 case 0x6F: return "01101111"; 1288 case 0x70: return "01110000"; 1289 case 0x71: return "01110001"; 1290 case 0x72: return "01110010"; 1291 case 0x73: return "01110011"; 1292 case 0x74: return "01110100"; 1293 case 0x75: return "01110101"; 1294 case 0x76: return "01110110"; 1295 case 0x77: return "01110111"; 1296 case 0x78: return "01111000"; 1297 case 0x79: return "01111001"; 1298 case 0x7A: return "01111010"; 1299 case 0x7B: return "01111011"; 1300 case 0x7C: return "01111100"; 1301 case 0x7D: return "01111101"; 1302 case 0x7E: return "01111110"; 1303 case 0x7F: return "01111111"; 1304 case 0x80: return "10000000"; 1305 case 0x81: return "10000001"; 1306 case 0x82: return "10000010"; 1307 case 0x83: return "10000011"; 1308 case 0x84: return "10000100"; 1309 case 0x85: return "10000101"; 1310 case 0x86: return "10000110"; 1311 case 0x87: return "10000111"; 1312 case 0x88: return "10001000"; 1313 case 0x89: return "10001001"; 1314 case 0x8A: return "10001010"; 1315 case 0x8B: return "10001011"; 1316 case 0x8C: return "10001100"; 1317 case 0x8D: return "10001101"; 1318 case 0x8E: return "10001110"; 1319 case 0x8F: return "10001111"; 1320 case 0x90: return "10010000"; 1321 case 0x91: return "10010001"; 1322 case 0x92: return "10010010"; 1323 case 0x93: return "10010011"; 1324 case 0x94: return "10010100"; 1325 case 0x95: return "10010101"; 1326 case 0x96: return "10010110"; 1327 case 0x97: return "10010111"; 1328 case 0x98: return "10011000"; 1329 case 0x99: return "10011001"; 1330 case 0x9A: return "10011010"; 1331 case 0x9B: return "10011011"; 1332 case 0x9C: return "10011100"; 1333 case 0x9D: return "10011101"; 1334 case 0x9E: return "10011110"; 1335 case 0x9F: return "10011111"; 1336 case 0xA0: return "10100000"; 1337 case 0xA1: return "10100001"; 1338 case 0xA2: return "10100010"; 1339 case 0xA3: return "10100011"; 1340 case 0xA4: return "10100100"; 1341 case 0xA5: return "10100101"; 1342 case 0xA6: return "10100110"; 1343 case 0xA7: return "10100111"; 1344 case 0xA8: return "10101000"; 1345 case 0xA9: return "10101001"; 1346 case 0xAA: return "10101010"; 1347 case 0xAB: return "10101011"; 1348 case 0xAC: return "10101100"; 1349 case 0xAD: return "10101101"; 1350 case 0xAE: return "10101110"; 1351 case 0xAF: return "10101111"; 1352 case 0xB0: return "10110000"; 1353 case 0xB1: return "10110001"; 1354 case 0xB2: return "10110010"; 1355 case 0xB3: return "10110011"; 1356 case 0xB4: return "10110100"; 1357 case 0xB5: return "10110101"; 1358 case 0xB6: return "10110110"; 1359 case 0xB7: return "10110111"; 1360 case 0xB8: return "10111000"; 1361 case 0xB9: return "10111001"; 1362 case 0xBA: return "10111010"; 1363 case 0xBB: return "10111011"; 1364 case 0xBC: return "10111100"; 1365 case 0xBD: return "10111101"; 1366 case 0xBE: return "10111110"; 1367 case 0xBF: return "10111111"; 1368 case 0xC0: return "11000000"; 1369 case 0xC1: return "11000001"; 1370 case 0xC2: return "11000010"; 1371 case 0xC3: return "11000011"; 1372 case 0xC4: return "11000100"; 1373 case 0xC5: return "11000101"; 1374 case 0xC6: return "11000110"; 1375 case 0xC7: return "11000111"; 1376 case 0xC8: return "11001000"; 1377 case 0xC9: return "11001001"; 1378 case 0xCA: return "11001010"; 1379 case 0xCB: return "11001011"; 1380 case 0xCC: return "11001100"; 1381 case 0xCD: return "11001101"; 1382 case 0xCE: return "11001110"; 1383 case 0xCF: return "11001111"; 1384 case 0xD0: return "11010000"; 1385 case 0xD1: return "11010001"; 1386 case 0xD2: return "11010010"; 1387 case 0xD3: return "11010011"; 1388 case 0xD4: return "11010100"; 1389 case 0xD5: return "11010101"; 1390 case 0xD6: return "11010110"; 1391 case 0xD7: return "11010111"; 1392 case 0xD8: return "11011000"; 1393 case 0xD9: return "11011001"; 1394 case 0xDA: return "11011010"; 1395 case 0xDB: return "11011011"; 1396 case 0xDC: return "11011100"; 1397 case 0xDD: return "11011101"; 1398 case 0xDE: return "11011110"; 1399 case 0xDF: return "11011111"; 1400 case 0xE0: return "11100000"; 1401 case 0xE1: return "11100001"; 1402 case 0xE2: return "11100010"; 1403 case 0xE3: return "11100011"; 1404 case 0xE4: return "11100100"; 1405 case 0xE5: return "11100101"; 1406 case 0xE6: return "11100110"; 1407 case 0xE7: return "11100111"; 1408 case 0xE8: return "11101000"; 1409 case 0xE9: return "11101001"; 1410 case 0xEA: return "11101010"; 1411 case 0xEB: return "11101011"; 1412 case 0xEC: return "11101100"; 1413 case 0xED: return "11101101"; 1414 case 0xEE: return "11101110"; 1415 case 0xEF: return "11101111"; 1416 case 0xF0: return "11110000"; 1417 case 0xF1: return "11110001"; 1418 case 0xF2: return "11110010"; 1419 case 0xF3: return "11110011"; 1420 case 0xF4: return "11110100"; 1421 case 0xF5: return "11110101"; 1422 case 0xF6: return "11110110"; 1423 case 0xF7: return "11110111"; 1424 case 0xF8: return "11111000"; 1425 case 0xF9: return "11111001"; 1426 case 0xFA: return "11111010"; 1427 case 0xFB: return "11111011"; 1428 case 0xFC: return "11111100"; 1429 case 0xFD: return "11111101"; 1430 case 0xFE: return "11111110"; 1431 case 0xFF: return "11111111"; 1432 default: return "????????"; 1433 } 1434 } 1435 1436 1437 1438 /** 1439 * Compare two byte arrays for order. Returns a negative integer, 1440 * zero, or a positive integer as the first argument is less than, 1441 * equal to, or greater than the second. 1442 * 1443 * @param a 1444 * The first byte array to be compared. 1445 * @param a2 1446 * The second byte array to be compared. 1447 * @return Returns a negative integer, zero, or a positive integer 1448 * if the first byte array is less than, equal to, or greater 1449 * than the second. 1450 */ 1451 public static int compare(byte[] a, byte[] a2) { 1452 if (a == a2) { 1453 return 0; 1454 } 1455 1456 if (a == null) { 1457 return -1; 1458 } 1459 1460 if (a2 == null) { 1461 return 1; 1462 } 1463 1464 int minLength = Math.min(a.length, a2.length); 1465 for (int i = 0; i < minLength; i++) { 1466 int firstByte = 0xFF & a[i]; 1467 int secondByte = 0xFF & a2[i]; 1468 if (firstByte != secondByte) { 1469 if (firstByte < secondByte) { 1470 return -1; 1471 } else if (firstByte > secondByte) { 1472 return 1; 1473 } 1474 } 1475 } 1476 1477 return a.length - a2.length; 1478 } 1479 1480 1481 1482 /** 1483 * Indicates whether the two array lists are equal. They will be 1484 * considered equal if they have the same number of elements, and 1485 * the corresponding elements between them are equal (in the same 1486 * order). 1487 * 1488 * @param list1 1489 * The first list for which to make the determination. 1490 * @param list2 1491 * The second list for which to make the determination. 1492 * @return <CODE>true</CODE> if the two array lists are equal, or 1493 * <CODE>false</CODE> if they are not. 1494 */ 1495 public static boolean listsAreEqual(List<?> list1, List<?> list2) 1496 { 1497 if (list1 == null) 1498 { 1499 return list2 == null; 1500 } 1501 else if (list2 == null) 1502 { 1503 return false; 1504 } 1505 1506 int numElements = list1.size(); 1507 if (numElements != list2.size()) 1508 { 1509 return false; 1510 } 1511 1512 // If either of the lists doesn't support random access, then fall back 1513 // on their equals methods and go ahead and create some garbage with the 1514 // iterators. 1515 if (!(list1 instanceof RandomAccess) || 1516 !(list2 instanceof RandomAccess)) 1517 { 1518 return list1.equals(list2); 1519 } 1520 1521 // Otherwise we can just retrieve the elements efficiently via their index. 1522 for (int i=0; i < numElements; i++) 1523 { 1524 Object o1 = list1.get(i); 1525 Object o2 = list2.get(i); 1526 1527 if (o1 == null) 1528 { 1529 if (o2 != null) 1530 { 1531 return false; 1532 } 1533 } 1534 else if (! o1.equals(o2)) 1535 { 1536 return false; 1537 } 1538 } 1539 1540 return true; 1541 } 1542 1543 /** 1544 * Retrieves the best human-readable message for the provided exception. For 1545 * exceptions defined in the OpenDJ project, it will attempt to use the 1546 * message (combining it with the message ID if available). For some 1547 * exceptions that use encapsulation (e.g., InvocationTargetException), it 1548 * will be unwrapped and the cause will be treated. For all others, the 1549 * 1550 * 1551 * @param t The {@code Throwable} object for which to retrieve the message. 1552 * 1553 * @return The human-readable message generated for the provided exception. 1554 */ 1555 public static LocalizableMessage getExceptionMessage(Throwable t) 1556 { 1557 if (t instanceof IdentifiedException) 1558 { 1559 IdentifiedException ie = (IdentifiedException) t; 1560 1561 StringBuilder message = new StringBuilder(); 1562 message.append(ie.getMessage()); 1563 message.append(" (id="); 1564 LocalizableMessage ieMsg = ie.getMessageObject(); 1565 if (ieMsg != null) { 1566 message.append(ieMsg.resourceName()).append("-").append(ieMsg.ordinal()); 1567 } else { 1568 message.append("-1"); 1569 } 1570 message.append(")"); 1571 return LocalizableMessage.raw(message.toString()); 1572 } 1573 else if (t instanceof NullPointerException) 1574 { 1575 LocalizableMessageBuilder message = new LocalizableMessageBuilder(); 1576 message.append("NullPointerException("); 1577 1578 StackTraceElement[] stackElements = t.getStackTrace(); 1579 if (stackElements.length > 0) 1580 { 1581 message.append(stackElements[0].getFileName()); 1582 message.append(":"); 1583 message.append(stackElements[0].getLineNumber()); 1584 } 1585 1586 message.append(")"); 1587 return message.toMessage(); 1588 } 1589 else if (t instanceof InvocationTargetException && t.getCause() != null) 1590 { 1591 return getExceptionMessage(t.getCause()); 1592 } 1593 else 1594 { 1595 StringBuilder message = new StringBuilder(); 1596 1597 String className = t.getClass().getName(); 1598 int periodPos = className.lastIndexOf('.'); 1599 if (periodPos > 0) 1600 { 1601 message.append(className.substring(periodPos+1)); 1602 } 1603 else 1604 { 1605 message.append(className); 1606 } 1607 1608 message.append("("); 1609 if (t.getMessage() == null) 1610 { 1611 StackTraceElement[] stackElements = t.getStackTrace(); 1612 1613 if (stackElements.length > 0) 1614 { 1615 message.append(stackElements[0].getFileName()); 1616 message.append(":"); 1617 message.append(stackElements[0].getLineNumber()); 1618 1619 // FIXME Temporary to debug issue 2256. 1620 if (t instanceof IllegalStateException) 1621 { 1622 for (int i = 1; i < stackElements.length; i++) 1623 { 1624 message.append(' '); 1625 message.append(stackElements[i].getFileName()); 1626 message.append(":"); 1627 message.append(stackElements[i].getLineNumber()); 1628 } 1629 } 1630 } 1631 } 1632 else 1633 { 1634 message.append(t.getMessage()); 1635 } 1636 1637 message.append(")"); 1638 1639 return LocalizableMessage.raw(message.toString()); 1640 } 1641 } 1642 1643 1644 1645 /** 1646 * Retrieves a stack trace from the provided exception as a single-line 1647 * string. 1648 * 1649 * @param t The exception for which to retrieve the stack trace. 1650 * 1651 * @return A stack trace from the provided exception as a single-line string. 1652 */ 1653 public static String stackTraceToSingleLineString(Throwable t) 1654 { 1655 return com.forgerock.opendj.util.StaticUtils.stackTraceToSingleLineString( 1656 t, DynamicConstants.DEBUG_BUILD); 1657 } 1658 1659 1660 1661 /** 1662 * Appends a single-line string representation of the provided exception to 1663 * the given buffer. 1664 * 1665 * @param buffer The buffer to which the information is to be appended. 1666 * @param t The exception for which to retrieve the stack trace. 1667 */ 1668 public static void stackTraceToSingleLineString(StringBuilder buffer, 1669 Throwable t) 1670 { 1671 com.forgerock.opendj.util.StaticUtils.stackTraceToSingleLineString( 1672 buffer, t, DynamicConstants.DEBUG_BUILD); 1673 } 1674 1675 1676 1677 /** 1678 * Retrieves a string representation of the stack trace for the provided 1679 * exception. 1680 * 1681 * @param t The exception for which to retrieve the stack trace. 1682 * 1683 * @return A string representation of the stack trace for the provided 1684 * exception. 1685 */ 1686 public static String stackTraceToString(Throwable t) 1687 { 1688 StringBuilder buffer = new StringBuilder(); 1689 stackTraceToString(buffer, t); 1690 return buffer.toString(); 1691 } 1692 1693 /** 1694 * Check if the stack trace of provided exception contains a given cause. 1695 * 1696 * @param throwable 1697 * exception that may contain the cause 1698 * @param searchedCause 1699 * class of the cause to look for. Any subclass will match. 1700 * @return true if and only if the given cause is found as a cause of any 1701 * level in the provided exception. 1702 */ 1703 public static boolean stackTraceContainsCause( 1704 Throwable throwable, Class<? extends Throwable> searchedCause) 1705 { 1706 Throwable t = throwable; 1707 while ((t = t.getCause()) != null) 1708 { 1709 if (searchedCause.isAssignableFrom(t.getClass())) 1710 { 1711 return true; 1712 } 1713 1714 } 1715 return false; 1716 } 1717 1718 /** 1719 * Appends a string representation of the stack trace for the provided 1720 * exception to the given buffer. 1721 * 1722 * @param buffer The buffer to which the information is to be appended. 1723 * @param t The exception for which to retrieve the stack trace. 1724 */ 1725 public static void stackTraceToString(StringBuilder buffer, Throwable t) 1726 { 1727 if (t == null) 1728 { 1729 return; 1730 } 1731 1732 buffer.append(t); 1733 1734 for (StackTraceElement e : t.getStackTrace()) 1735 { 1736 buffer.append(EOL); 1737 buffer.append(" "); 1738 buffer.append(e.getClassName()); 1739 buffer.append("."); 1740 buffer.append(e.getMethodName()); 1741 buffer.append("("); 1742 buffer.append(e.getFileName()); 1743 buffer.append(":"); 1744 buffer.append(e.getLineNumber()); 1745 buffer.append(")"); 1746 } 1747 1748 while (t.getCause() != null) 1749 { 1750 t = t.getCause(); 1751 buffer.append(EOL); 1752 buffer.append("Caused by "); 1753 buffer.append(t); 1754 1755 for (StackTraceElement e : t.getStackTrace()) 1756 { 1757 buffer.append(EOL); 1758 buffer.append(" "); 1759 buffer.append(e.getClassName()); 1760 buffer.append("."); 1761 buffer.append(e.getMethodName()); 1762 buffer.append("("); 1763 buffer.append(e.getFileName()); 1764 buffer.append(":"); 1765 buffer.append(e.getLineNumber()); 1766 buffer.append(")"); 1767 } 1768 } 1769 1770 buffer.append(EOL); 1771 } 1772 1773 1774 1775 /** 1776 * Retrieves a backtrace for the current thread consisting only of filenames 1777 * and line numbers that may be useful in debugging the origin of problems 1778 * that should not have happened. Note that this may be an expensive 1779 * operation to perform, so it should only be used for error conditions or 1780 * debugging. 1781 * 1782 * @return A backtrace for the current thread. 1783 */ 1784 public static String getBacktrace() 1785 { 1786 StringBuilder buffer = new StringBuilder(); 1787 1788 StackTraceElement[] elements = Thread.currentThread().getStackTrace(); 1789 1790 if (elements.length > 1) 1791 { 1792 buffer.append(elements[1].getFileName()); 1793 buffer.append(":"); 1794 buffer.append(elements[1].getLineNumber()); 1795 1796 for (int i=2; i < elements.length; i++) 1797 { 1798 buffer.append(" "); 1799 buffer.append(elements[i].getFileName()); 1800 buffer.append(":"); 1801 buffer.append(elements[i].getLineNumber()); 1802 } 1803 } 1804 1805 return buffer.toString(); 1806 } 1807 1808 1809 1810 /** 1811 * Retrieves a backtrace for the provided exception consisting of only 1812 * filenames and line numbers that may be useful in debugging the origin of 1813 * problems. This is less expensive than the call to 1814 * <CODE>getBacktrace</CODE> without any arguments if an exception has already 1815 * been thrown. 1816 * 1817 * @param t The exception for which to obtain the backtrace. 1818 * 1819 * @return A backtrace from the provided exception. 1820 */ 1821 public static String getBacktrace(Throwable t) 1822 { 1823 StringBuilder buffer = new StringBuilder(); 1824 1825 StackTraceElement[] elements = t.getStackTrace(); 1826 1827 if (elements.length > 0) 1828 { 1829 buffer.append(elements[0].getFileName()); 1830 buffer.append(":"); 1831 buffer.append(elements[0].getLineNumber()); 1832 1833 for (int i=1; i < elements.length; i++) 1834 { 1835 buffer.append(" "); 1836 buffer.append(elements[i].getFileName()); 1837 buffer.append(":"); 1838 buffer.append(elements[i].getLineNumber()); 1839 } 1840 } 1841 1842 return buffer.toString(); 1843 } 1844 1845 1846 1847 /** 1848 * Indicates whether the provided character is a numeric digit. 1849 * 1850 * @param c The character for which to make the determination. 1851 * 1852 * @return <CODE>true</CODE> if the provided character represents a numeric 1853 * digit, or <CODE>false</CODE> if not. 1854 */ 1855 public static boolean isDigit(char c) 1856 { 1857 switch (c) 1858 { 1859 case '0': 1860 case '1': 1861 case '2': 1862 case '3': 1863 case '4': 1864 case '5': 1865 case '6': 1866 case '7': 1867 case '8': 1868 case '9': 1869 return true; 1870 default: 1871 return false; 1872 } 1873 } 1874 1875 1876 1877 /** 1878 * Indicates whether the provided character is an ASCII alphabetic character. 1879 * 1880 * @param c The character for which to make the determination. 1881 * 1882 * @return <CODE>true</CODE> if the provided value is an uppercase or 1883 * lowercase ASCII alphabetic character, or <CODE>false</CODE> if it 1884 * is not. 1885 */ 1886 public static boolean isAlpha(char c) 1887 { 1888 switch (c) 1889 { 1890 case 'A': 1891 case 'B': 1892 case 'C': 1893 case 'D': 1894 case 'E': 1895 case 'F': 1896 case 'G': 1897 case 'H': 1898 case 'I': 1899 case 'J': 1900 case 'K': 1901 case 'L': 1902 case 'M': 1903 case 'N': 1904 case 'O': 1905 case 'P': 1906 case 'Q': 1907 case 'R': 1908 case 'S': 1909 case 'T': 1910 case 'U': 1911 case 'V': 1912 case 'W': 1913 case 'X': 1914 case 'Y': 1915 case 'Z': 1916 return true; 1917 1918 case '[': 1919 case '\\': 1920 case ']': 1921 case '^': 1922 case '_': 1923 case '`': 1924 // Making sure all possible cases are present in one contiguous range 1925 // can result in a performance improvement. 1926 return false; 1927 1928 case 'a': 1929 case 'b': 1930 case 'c': 1931 case 'd': 1932 case 'e': 1933 case 'f': 1934 case 'g': 1935 case 'h': 1936 case 'i': 1937 case 'j': 1938 case 'k': 1939 case 'l': 1940 case 'm': 1941 case 'n': 1942 case 'o': 1943 case 'p': 1944 case 'q': 1945 case 'r': 1946 case 's': 1947 case 't': 1948 case 'u': 1949 case 'v': 1950 case 'w': 1951 case 'x': 1952 case 'y': 1953 case 'z': 1954 return true; 1955 default: 1956 return false; 1957 } 1958 } 1959 1960 1961 1962 /** 1963 * Indicates whether the provided character is a hexadecimal digit. 1964 * 1965 * @param c The character for which to make the determination. 1966 * 1967 * @return <CODE>true</CODE> if the provided character represents a 1968 * hexadecimal digit, or <CODE>false</CODE> if not. 1969 */ 1970 public static boolean isHexDigit(char c) 1971 { 1972 switch (c) 1973 { 1974 case '0': 1975 case '1': 1976 case '2': 1977 case '3': 1978 case '4': 1979 case '5': 1980 case '6': 1981 case '7': 1982 case '8': 1983 case '9': 1984 case 'A': 1985 case 'B': 1986 case 'C': 1987 case 'D': 1988 case 'E': 1989 case 'F': 1990 case 'a': 1991 case 'b': 1992 case 'c': 1993 case 'd': 1994 case 'e': 1995 case 'f': 1996 return true; 1997 default: 1998 return false; 1999 } 2000 } 2001 2002 2003 2004 /** 2005 * Indicates whether the provided byte represents a hexadecimal digit. 2006 * 2007 * @param b The byte for which to make the determination. 2008 * 2009 * @return <CODE>true</CODE> if the provided byte represents a hexadecimal 2010 * digit, or <CODE>false</CODE> if not. 2011 */ 2012 public static boolean isHexDigit(byte b) 2013 { 2014 switch (b) 2015 { 2016 case '0': 2017 case '1': 2018 case '2': 2019 case '3': 2020 case '4': 2021 case '5': 2022 case '6': 2023 case '7': 2024 case '8': 2025 case '9': 2026 case 'A': 2027 case 'B': 2028 case 'C': 2029 case 'D': 2030 case 'E': 2031 case 'F': 2032 case 'a': 2033 case 'b': 2034 case 'c': 2035 case 'd': 2036 case 'e': 2037 case 'f': 2038 return true; 2039 default: 2040 return false; 2041 } 2042 } 2043 2044 2045 2046 /** 2047 * Converts the provided hexadecimal string to a byte array. 2048 * 2049 * @param hexString The hexadecimal string to convert to a byte array. 2050 * 2051 * @return The byte array containing the binary representation of the 2052 * provided hex string. 2053 * 2054 * @throws ParseException If the provided string contains invalid 2055 * hexadecimal digits or does not contain an even 2056 * number of digits. 2057 */ 2058 public static byte[] hexStringToByteArray(String hexString) 2059 throws ParseException 2060 { 2061 int length; 2062 if (hexString == null || ((length = hexString.length()) == 0)) 2063 { 2064 return new byte[0]; 2065 } 2066 2067 2068 if ((length % 2) == 1) 2069 { 2070 LocalizableMessage message = ERR_HEX_DECODE_INVALID_LENGTH.get(hexString); 2071 throw new ParseException(message.toString(), 0); 2072 } 2073 2074 2075 int pos = 0; 2076 int arrayLength = length / 2; 2077 byte[] returnArray = new byte[arrayLength]; 2078 for (int i=0; i < arrayLength; i++) 2079 { 2080 switch (hexString.charAt(pos++)) 2081 { 2082 case '0': 2083 returnArray[i] = 0x00; 2084 break; 2085 case '1': 2086 returnArray[i] = 0x10; 2087 break; 2088 case '2': 2089 returnArray[i] = 0x20; 2090 break; 2091 case '3': 2092 returnArray[i] = 0x30; 2093 break; 2094 case '4': 2095 returnArray[i] = 0x40; 2096 break; 2097 case '5': 2098 returnArray[i] = 0x50; 2099 break; 2100 case '6': 2101 returnArray[i] = 0x60; 2102 break; 2103 case '7': 2104 returnArray[i] = 0x70; 2105 break; 2106 case '8': 2107 returnArray[i] = (byte) 0x80; 2108 break; 2109 case '9': 2110 returnArray[i] = (byte) 0x90; 2111 break; 2112 case 'A': 2113 case 'a': 2114 returnArray[i] = (byte) 0xA0; 2115 break; 2116 case 'B': 2117 case 'b': 2118 returnArray[i] = (byte) 0xB0; 2119 break; 2120 case 'C': 2121 case 'c': 2122 returnArray[i] = (byte) 0xC0; 2123 break; 2124 case 'D': 2125 case 'd': 2126 returnArray[i] = (byte) 0xD0; 2127 break; 2128 case 'E': 2129 case 'e': 2130 returnArray[i] = (byte) 0xE0; 2131 break; 2132 case 'F': 2133 case 'f': 2134 returnArray[i] = (byte) 0xF0; 2135 break; 2136 default: 2137 LocalizableMessage message = ERR_HEX_DECODE_INVALID_CHARACTER.get( 2138 hexString, hexString.charAt(pos-1)); 2139 throw new ParseException(message.toString(), 0); 2140 } 2141 2142 switch (hexString.charAt(pos++)) 2143 { 2144 case '0': 2145 // No action required. 2146 break; 2147 case '1': 2148 returnArray[i] |= 0x01; 2149 break; 2150 case '2': 2151 returnArray[i] |= 0x02; 2152 break; 2153 case '3': 2154 returnArray[i] |= 0x03; 2155 break; 2156 case '4': 2157 returnArray[i] |= 0x04; 2158 break; 2159 case '5': 2160 returnArray[i] |= 0x05; 2161 break; 2162 case '6': 2163 returnArray[i] |= 0x06; 2164 break; 2165 case '7': 2166 returnArray[i] |= 0x07; 2167 break; 2168 case '8': 2169 returnArray[i] |= 0x08; 2170 break; 2171 case '9': 2172 returnArray[i] |= 0x09; 2173 break; 2174 case 'A': 2175 case 'a': 2176 returnArray[i] |= 0x0A; 2177 break; 2178 case 'B': 2179 case 'b': 2180 returnArray[i] |= 0x0B; 2181 break; 2182 case 'C': 2183 case 'c': 2184 returnArray[i] |= 0x0C; 2185 break; 2186 case 'D': 2187 case 'd': 2188 returnArray[i] |= 0x0D; 2189 break; 2190 case 'E': 2191 case 'e': 2192 returnArray[i] |= 0x0E; 2193 break; 2194 case 'F': 2195 case 'f': 2196 returnArray[i] |= 0x0F; 2197 break; 2198 default: 2199 LocalizableMessage message = ERR_HEX_DECODE_INVALID_CHARACTER.get( 2200 hexString, hexString.charAt(pos-1)); 2201 throw new ParseException(message.toString(), 0); 2202 } 2203 } 2204 2205 return returnArray; 2206 } 2207 2208 2209 2210 /** 2211 * Indicates whether the provided value needs to be base64-encoded if it is 2212 * represented in LDIF form. 2213 * 2214 * @param valueBytes The binary representation of the attribute value for 2215 * which to make the determination. 2216 * 2217 * @return <CODE>true</CODE> if the value needs to be base64-encoded if it is 2218 * represented in LDIF form, or <CODE>false</CODE> if not. 2219 */ 2220 public static boolean needsBase64Encoding(ByteSequence valueBytes) 2221 { 2222 int length; 2223 if (valueBytes == null || ((length = valueBytes.length()) == 0)) 2224 { 2225 return false; 2226 } 2227 2228 2229 // If the value starts with a space, colon, or less than, then it needs to 2230 // be base64-encoded. 2231 switch (valueBytes.byteAt(0)) 2232 { 2233 case 0x20: // Space 2234 case 0x3A: // Colon 2235 case 0x3C: // Less-than 2236 return true; 2237 } 2238 2239 2240 // If the value ends with a space, then it needs to be base64-encoded. 2241 if (length > 1 && valueBytes.byteAt(length-1) == 0x20) 2242 { 2243 return true; 2244 } 2245 2246 2247 // If the value contains a null, newline, or return character, then it needs 2248 // to be base64-encoded. 2249 byte b; 2250 for (int i = 0; i < valueBytes.length(); i++) 2251 { 2252 b = valueBytes.byteAt(i); 2253 if (b < 0 || 127 < b) 2254 { 2255 return true; 2256 } 2257 2258 switch (b) 2259 { 2260 case 0x00: // Null 2261 case 0x0A: // New line 2262 case 0x0D: // Carriage return 2263 return true; 2264 } 2265 } 2266 2267 2268 // If we've made it here, then there's no reason to base64-encode. 2269 return false; 2270 } 2271 2272 2273 2274 /** 2275 * Indicates whether the provided value needs to be base64-encoded if it is 2276 * represented in LDIF form. 2277 * 2278 * @param valueString The string representation of the attribute value for 2279 * which to make the determination. 2280 * 2281 * @return <CODE>true</CODE> if the value needs to be base64-encoded if it is 2282 * represented in LDIF form, or <CODE>false</CODE> if not. 2283 */ 2284 public static boolean needsBase64Encoding(String valueString) 2285 { 2286 int length; 2287 if (valueString == null || ((length = valueString.length()) == 0)) 2288 { 2289 return false; 2290 } 2291 2292 2293 // If the value starts with a space, colon, or less than, then it needs to 2294 // be base64-encoded. 2295 switch (valueString.charAt(0)) 2296 { 2297 case ' ': 2298 case ':': 2299 case '<': 2300 return true; 2301 } 2302 2303 2304 // If the value ends with a space, then it needs to be base64-encoded. 2305 if (length > 1 && valueString.charAt(length-1) == ' ') 2306 { 2307 return true; 2308 } 2309 2310 2311 // If the value contains a null, newline, or return character, then it needs 2312 // to be base64-encoded. 2313 for (int i=0; i < length; i++) 2314 { 2315 char c = valueString.charAt(i); 2316 if (c <= 0 || c == 0x0A || c == 0x0D || c > 127) 2317 { 2318 return true; 2319 } 2320 } 2321 2322 2323 // If we've made it here, then there's no reason to base64-encode. 2324 return false; 2325 } 2326 2327 2328 2329 /** 2330 * Indicates whether the use of the exec method will be allowed on this 2331 * system. It will be allowed by default, but that capability will be removed 2332 * if the org.opends.server.DisableExec system property is set and has any 2333 * value other than "false", "off", "no", or "0". 2334 * 2335 * @return <CODE>true</CODE> if the use of the exec method should be allowed, 2336 * or <CODE>false</CODE> if it should not be allowed. 2337 */ 2338 public static boolean mayUseExec() 2339 { 2340 return !DirectoryServer.getEnvironmentConfig().disableExec(); 2341 } 2342 2343 2344 2345 /** 2346 * Executes the specified command on the system and captures its output. This 2347 * will not return until the specified process has completed. 2348 * 2349 * @param command The command to execute. 2350 * @param args The set of arguments to provide to the command. 2351 * @param workingDirectory The working directory to use for the command, or 2352 * <CODE>null</CODE> if the default directory 2353 * should be used. 2354 * @param environment The set of environment variables that should be 2355 * set when executing the command, or 2356 * <CODE>null</CODE> if none are needed. 2357 * @param output The output generated by the command while it was 2358 * running. This will include both standard 2359 * output and standard error. It may be 2360 * <CODE>null</CODE> if the output does not need to 2361 * be captured. 2362 * 2363 * @return The exit code for the command. 2364 * 2365 * @throws IOException If an I/O problem occurs while trying to execute the 2366 * command. 2367 * 2368 * @throws SecurityException If the security policy will not allow the 2369 * command to be executed. 2370 * 2371 * @throws InterruptedException If the current thread is interrupted by 2372 * another thread while it is waiting, then 2373 * the wait is ended and an InterruptedException 2374 * is thrown. 2375 */ 2376 public static int exec(String command, String[] args, File workingDirectory, 2377 Map<String,String> environment, List<String> output) 2378 throws IOException, SecurityException, InterruptedException 2379 { 2380 // See whether we'll allow the use of exec on this system. If not, then 2381 // throw an exception. 2382 if (! mayUseExec()) 2383 { 2384 throw new SecurityException(ERR_EXEC_DISABLED.get(command).toString()); 2385 } 2386 2387 2388 ArrayList<String> commandAndArgs = new ArrayList<>(); 2389 commandAndArgs.add(command); 2390 if (args != null && args.length > 0) 2391 { 2392 Collections.addAll(commandAndArgs, args); 2393 } 2394 2395 ProcessBuilder processBuilder = new ProcessBuilder(commandAndArgs); 2396 processBuilder.redirectErrorStream(true); 2397 2398 if (workingDirectory != null && workingDirectory.isDirectory()) 2399 { 2400 processBuilder.directory(workingDirectory); 2401 } 2402 2403 if (environment != null && !environment.isEmpty()) 2404 { 2405 processBuilder.environment().putAll(environment); 2406 } 2407 2408 Process process = processBuilder.start(); 2409 2410 // We must exhaust stdout and stderr before calling waitfor. Since we 2411 // redirected the error stream, we just have to read from stdout. 2412 InputStream processStream = process.getInputStream(); 2413 BufferedReader reader = 2414 new BufferedReader(new InputStreamReader(processStream)); 2415 String line = null; 2416 2417 try 2418 { 2419 while((line = reader.readLine()) != null) 2420 { 2421 if(output != null) 2422 { 2423 output.add(line); 2424 } 2425 } 2426 } 2427 catch(IOException ioe) 2428 { 2429 // If this happens, then we have no choice but to forcefully terminate 2430 // the process. 2431 try 2432 { 2433 process.destroy(); 2434 } 2435 catch (Exception e) 2436 { 2437 logger.traceException(e); 2438 } 2439 2440 throw ioe; 2441 } 2442 finally 2443 { 2444 try 2445 { 2446 reader.close(); 2447 } 2448 catch(IOException e) 2449 { 2450 logger.traceException(e); 2451 } 2452 } 2453 2454 return process.waitFor(); 2455 } 2456 2457 2458 2459 /** 2460 * Indicates whether the provided string contains a name or OID for a schema 2461 * element like an attribute type or objectclass. 2462 * 2463 * @param element The string containing the substring for which to 2464 * make the determination. 2465 * @param startPos The position of the first character that is to be 2466 * checked. 2467 * @param endPos The position of the first character after the start 2468 * position that is not to be checked. 2469 * @param invalidReason The buffer to which the invalid reason is to be 2470 * appended if a problem is found. 2471 * 2472 * @return <CODE>true</CODE> if the provided string contains a valid name or 2473 * OID for a schema element, or <CODE>false</CODE> if it does not. 2474 */ 2475 public static boolean isValidSchemaElement(String element, int startPos, 2476 int endPos, 2477 LocalizableMessageBuilder invalidReason) 2478 { 2479 if (element == null || startPos >= endPos) 2480 { 2481 invalidReason.append(ERR_SCHEMANAME_EMPTY_VALUE.get()); 2482 return false; 2483 } 2484 2485 2486 char c = element.charAt(startPos); 2487 if (isAlpha(c)) 2488 { 2489 // This can only be a name and not an OID. The only remaining characters 2490 // must be letters, digits, dashes, and possibly the underscore. 2491 for (int i=startPos+1; i < endPos; i++) 2492 { 2493 c = element.charAt(i); 2494 if (!isAlpha(c) 2495 && !isDigit(c) 2496 && c != '-' 2497 && (c != '_' || !DirectoryServer.allowAttributeNameExceptions())) 2498 { 2499 // This is an illegal character for an attribute name. 2500 invalidReason.append(ERR_SCHEMANAME_ILLEGAL_CHAR.get(element, c, i)); 2501 return false; 2502 } 2503 } 2504 } 2505 else if (isDigit(c)) 2506 { 2507 // This should indicate an OID, but it may also be a name if name 2508 // exceptions are enabled. Since we don't know for sure, we'll just 2509 // hold off until we know for sure. 2510 boolean isKnown = !DirectoryServer.allowAttributeNameExceptions(); 2511 boolean isNumeric = true; 2512 boolean lastWasDot = false; 2513 2514 for (int i=startPos+1; i < endPos; i++) 2515 { 2516 c = element.charAt(i); 2517 if (c == '.') 2518 { 2519 if (isKnown) 2520 { 2521 if (isNumeric) 2522 { 2523 // This is probably legal unless the last character was also a 2524 // period. 2525 if (lastWasDot) 2526 { 2527 invalidReason.append(ERR_SCHEMANAME_CONSECUTIVE_PERIODS.get( 2528 element, i)); 2529 return false; 2530 } 2531 else 2532 { 2533 lastWasDot = true; 2534 } 2535 } 2536 else 2537 { 2538 // This is an illegal character. 2539 invalidReason.append(ERR_SCHEMANAME_ILLEGAL_CHAR.get( 2540 element, c, i)); 2541 return false; 2542 } 2543 } 2544 else 2545 { 2546 // Now we know that this must be a numeric OID and not an attribute 2547 // name with exceptions allowed. 2548 lastWasDot = true; 2549 isKnown = true; 2550 isNumeric = true; 2551 } 2552 } 2553 else 2554 { 2555 lastWasDot = false; 2556 2557 if (isAlpha(c) || c == '-' || c == '_') 2558 { 2559 if (isKnown) 2560 { 2561 if (isNumeric) 2562 { 2563 // This is an illegal character for a numeric OID. 2564 invalidReason.append(ERR_SCHEMANAME_ILLEGAL_CHAR.get( 2565 element, c, i)); 2566 return false; 2567 } 2568 } 2569 else 2570 { 2571 // Now we know that this must be an attribute name with exceptions 2572 // allowed and not a numeric OID. 2573 isKnown = true; 2574 isNumeric = false; 2575 } 2576 } 2577 else if (! isDigit(c)) 2578 { 2579 // This is an illegal character. 2580 invalidReason.append(ERR_SCHEMANAME_ILLEGAL_CHAR.get( 2581 element, c, i)); 2582 return false; 2583 } 2584 } 2585 } 2586 } 2587 else 2588 { 2589 // This is an illegal character. 2590 invalidReason.append(ERR_SCHEMANAME_ILLEGAL_CHAR.get( 2591 element, c, startPos)); 2592 return false; 2593 } 2594 2595 2596 // If we've gotten here, then the value is fine. 2597 return true; 2598 } 2599 2600 2601 2602 /** 2603 * Indicates whether the provided TCP address is already in use. 2604 * 2605 * @param address IP address of the TCP address for which to make 2606 * the determination. 2607 * @param port TCP port number of the TCP address for which to 2608 * make the determination. 2609 * @param allowReuse Whether or not TCP address reuse is allowed when 2610 * making the determination. 2611 * 2612 * @return <CODE>true</CODE> if the provided TCP address is already in 2613 * use, or <CODE>false</CODE> otherwise. 2614 */ 2615 public static boolean isAddressInUse( 2616 InetAddress address, int port, 2617 boolean allowReuse) 2618 { 2619 // Return pessimistic. 2620 boolean isInUse = true; 2621 Socket clientSocket = null; 2622 ServerSocket serverSocket = null; 2623 try { 2624 // HACK: 2625 // With dual stacks we can have a situation when INADDR_ANY/PORT 2626 // is bound in TCP4 space but available in TCP6 space and since 2627 // JavaServerSocket implemantation will always use TCP46 on dual 2628 // stacks the bind below will always succeed in such cases thus 2629 // shadowing anything that is already bound to INADDR_ANY/PORT. 2630 // While technically correct, with IPv4 and IPv6 being separate 2631 // address spaces, it presents a problem to end users because a 2632 // common case scenario is to have a single service serving both 2633 // address spaces ie listening to the same port in both spaces 2634 // on wildcard addresses 0 and ::. ServerSocket implemantation 2635 // does not provide any means of working with each address space 2636 // separately such as doing TCP4 or TCP6 only binds thus we have 2637 // to do a dummy connect to INADDR_ANY/PORT to check if it is 2638 // bound to something already. This is only needed for wildcard 2639 // addresses as specific IPv4 or IPv6 addresses will always be 2640 // handled in their respective address space. 2641 if (address.isAnyLocalAddress()) { 2642 clientSocket = new Socket(); 2643 try { 2644 // This might fail on some stacks but this is the best we 2645 // can do. No need for explicit timeout since it is local 2646 // address and we have to know for sure unless it fails. 2647 clientSocket.connect(new InetSocketAddress(address, port)); 2648 } catch (IOException e) { 2649 // Expected, ignore. 2650 } 2651 if (clientSocket.isConnected()) { 2652 return true; 2653 } 2654 } 2655 serverSocket = new ServerSocket(); 2656 serverSocket.setReuseAddress(allowReuse); 2657 serverSocket.bind(new InetSocketAddress(address, port)); 2658 isInUse = false; 2659 } catch (IOException e) { 2660 isInUse = true; 2661 } finally { 2662 try { 2663 if (serverSocket != null) { 2664 serverSocket.close(); 2665 } 2666 } catch (Exception e) {} 2667 try { 2668 if (clientSocket != null) { 2669 clientSocket.close(); 2670 } 2671 } catch (Exception e) {} 2672 } 2673 return isInUse; 2674 } 2675 2676 2677 2678 /** 2679 * Retrieves a lowercase representation of the given string. This 2680 * implementation presumes that the provided string will contain only ASCII 2681 * characters and is optimized for that case. However, if a non-ASCII 2682 * character is encountered it will fall back on a more expensive algorithm 2683 * that will work properly for non-ASCII characters. 2684 * 2685 * @param s The string for which to obtain the lowercase representation. 2686 * 2687 * @return The lowercase representation of the given string. 2688 */ 2689 public static String toLowerCase(String s) 2690 { 2691 if (s == null) 2692 { 2693 return null; 2694 } 2695 2696 StringBuilder buffer = new StringBuilder(s.length()); 2697 toLowerCase(s, buffer); 2698 return buffer.toString(); 2699 } 2700 2701 2702 2703 /** 2704 * Appends a lowercase representation of the given string to the provided 2705 * buffer. This implementation presumes that the provided string will contain 2706 * only ASCII characters and is optimized for that case. However, if a 2707 * non-ASCII character is encountered it will fall back on a more expensive 2708 * algorithm that will work properly for non-ASCII characters. 2709 * 2710 * @param s The string for which to obtain the lowercase 2711 * representation. 2712 * @param buffer The buffer to which the lowercase form of the string should 2713 * be appended. 2714 */ 2715 public static void toLowerCase(String s, StringBuilder buffer) 2716 { 2717 if (s == null) 2718 { 2719 return; 2720 } 2721 2722 int length = s.length(); 2723 for (int i=0; i < length; i++) 2724 { 2725 char c = s.charAt(i); 2726 2727 if ((c & 0x7F) != c) 2728 { 2729 buffer.append(s.substring(i).toLowerCase()); 2730 return; 2731 } 2732 2733 switch (c) 2734 { 2735 case 'A': 2736 buffer.append('a'); 2737 break; 2738 case 'B': 2739 buffer.append('b'); 2740 break; 2741 case 'C': 2742 buffer.append('c'); 2743 break; 2744 case 'D': 2745 buffer.append('d'); 2746 break; 2747 case 'E': 2748 buffer.append('e'); 2749 break; 2750 case 'F': 2751 buffer.append('f'); 2752 break; 2753 case 'G': 2754 buffer.append('g'); 2755 break; 2756 case 'H': 2757 buffer.append('h'); 2758 break; 2759 case 'I': 2760 buffer.append('i'); 2761 break; 2762 case 'J': 2763 buffer.append('j'); 2764 break; 2765 case 'K': 2766 buffer.append('k'); 2767 break; 2768 case 'L': 2769 buffer.append('l'); 2770 break; 2771 case 'M': 2772 buffer.append('m'); 2773 break; 2774 case 'N': 2775 buffer.append('n'); 2776 break; 2777 case 'O': 2778 buffer.append('o'); 2779 break; 2780 case 'P': 2781 buffer.append('p'); 2782 break; 2783 case 'Q': 2784 buffer.append('q'); 2785 break; 2786 case 'R': 2787 buffer.append('r'); 2788 break; 2789 case 'S': 2790 buffer.append('s'); 2791 break; 2792 case 'T': 2793 buffer.append('t'); 2794 break; 2795 case 'U': 2796 buffer.append('u'); 2797 break; 2798 case 'V': 2799 buffer.append('v'); 2800 break; 2801 case 'W': 2802 buffer.append('w'); 2803 break; 2804 case 'X': 2805 buffer.append('x'); 2806 break; 2807 case 'Y': 2808 buffer.append('y'); 2809 break; 2810 case 'Z': 2811 buffer.append('z'); 2812 break; 2813 default: 2814 buffer.append(c); 2815 } 2816 } 2817 } 2818 2819 2820 2821 /** 2822 * Appends a lowercase string representation of the contents of the given byte 2823 * array to the provided buffer, optionally trimming leading and trailing 2824 * spaces. This implementation presumes that the provided string will contain 2825 * only ASCII characters and is optimized for that case. However, if a 2826 * non-ASCII character is encountered it will fall back on a more expensive 2827 * algorithm that will work properly for non-ASCII characters. 2828 * 2829 * @param b The byte array for which to obtain the lowercase string 2830 * representation. 2831 * @param buffer The buffer to which the lowercase form of the string should 2832 * be appended. 2833 * @param trim Indicates whether leading and trailing spaces should be 2834 * omitted from the string representation. 2835 */ 2836 public static void toLowerCase(ByteSequence b, StringBuilder buffer, 2837 boolean trim) 2838 { 2839 if (b == null) 2840 { 2841 return; 2842 } 2843 2844 int origBufferLen = buffer.length(); 2845 int length = b.length(); 2846 for (int i=0; i < length; i++) 2847 { 2848 if ((b.byteAt(i) & 0x7F) != b.byteAt(i)) 2849 { 2850 buffer.replace(origBufferLen, buffer.length(), 2851 b.toString().toLowerCase()); 2852 break; 2853 } 2854 2855 int bufferLength = buffer.length(); 2856 switch (b.byteAt(i)) 2857 { 2858 case ' ': 2859 // If we don't care about trimming, then we can always append the 2860 // space. Otherwise, only do so if there are other characters in the value. 2861 if (trim && bufferLength == 0) 2862 { 2863 break; 2864 } 2865 2866 buffer.append(' '); 2867 break; 2868 case 'A': 2869 buffer.append('a'); 2870 break; 2871 case 'B': 2872 buffer.append('b'); 2873 break; 2874 case 'C': 2875 buffer.append('c'); 2876 break; 2877 case 'D': 2878 buffer.append('d'); 2879 break; 2880 case 'E': 2881 buffer.append('e'); 2882 break; 2883 case 'F': 2884 buffer.append('f'); 2885 break; 2886 case 'G': 2887 buffer.append('g'); 2888 break; 2889 case 'H': 2890 buffer.append('h'); 2891 break; 2892 case 'I': 2893 buffer.append('i'); 2894 break; 2895 case 'J': 2896 buffer.append('j'); 2897 break; 2898 case 'K': 2899 buffer.append('k'); 2900 break; 2901 case 'L': 2902 buffer.append('l'); 2903 break; 2904 case 'M': 2905 buffer.append('m'); 2906 break; 2907 case 'N': 2908 buffer.append('n'); 2909 break; 2910 case 'O': 2911 buffer.append('o'); 2912 break; 2913 case 'P': 2914 buffer.append('p'); 2915 break; 2916 case 'Q': 2917 buffer.append('q'); 2918 break; 2919 case 'R': 2920 buffer.append('r'); 2921 break; 2922 case 'S': 2923 buffer.append('s'); 2924 break; 2925 case 'T': 2926 buffer.append('t'); 2927 break; 2928 case 'U': 2929 buffer.append('u'); 2930 break; 2931 case 'V': 2932 buffer.append('v'); 2933 break; 2934 case 'W': 2935 buffer.append('w'); 2936 break; 2937 case 'X': 2938 buffer.append('x'); 2939 break; 2940 case 'Y': 2941 buffer.append('y'); 2942 break; 2943 case 'Z': 2944 buffer.append('z'); 2945 break; 2946 default: 2947 buffer.append((char) b.byteAt(i)); 2948 } 2949 } 2950 2951 if (trim) 2952 { 2953 // Strip off any trailing spaces. 2954 for (int i=buffer.length()-1; i > 0; i--) 2955 { 2956 if (buffer.charAt(i) == ' ') 2957 { 2958 buffer.delete(i, i+1); 2959 } 2960 else 2961 { 2962 break; 2963 } 2964 } 2965 } 2966 } 2967 2968 2969 2970 /** 2971 * Retrieves an uppercase representation of the given string. This 2972 * implementation presumes that the provided string will contain only ASCII 2973 * characters and is optimized for that case. However, if a non-ASCII 2974 * character is encountered it will fall back on a more expensive algorithm 2975 * that will work properly for non-ASCII characters. 2976 * 2977 * @param s The string for which to obtain the uppercase representation. 2978 * 2979 * @return The uppercase representation of the given string. 2980 */ 2981 public static String toUpperCase(String s) 2982 { 2983 if (s == null) 2984 { 2985 return null; 2986 } 2987 2988 StringBuilder buffer = new StringBuilder(s.length()); 2989 toUpperCase(s, buffer); 2990 return buffer.toString(); 2991 } 2992 2993 2994 2995 /** 2996 * Appends an uppercase representation of the given string to the provided 2997 * buffer. This implementation presumes that the provided string will contain 2998 * only ASCII characters and is optimized for that case. However, if a 2999 * non-ASCII character is encountered it will fall back on a more expensive 3000 * algorithm that will work properly for non-ASCII characters. 3001 * 3002 * @param s The string for which to obtain the uppercase 3003 * representation. 3004 * @param buffer The buffer to which the uppercase form of the string should 3005 * be appended. 3006 */ 3007 public static void toUpperCase(String s, StringBuilder buffer) 3008 { 3009 if (s == null) 3010 { 3011 return; 3012 } 3013 3014 int length = s.length(); 3015 for (int i=0; i < length; i++) 3016 { 3017 char c = s.charAt(i); 3018 3019 if ((c & 0x7F) != c) 3020 { 3021 buffer.append(s.substring(i).toUpperCase()); 3022 return; 3023 } 3024 3025 switch (c) 3026 { 3027 case 'a': 3028 buffer.append('A'); 3029 break; 3030 case 'b': 3031 buffer.append('B'); 3032 break; 3033 case 'c': 3034 buffer.append('C'); 3035 break; 3036 case 'd': 3037 buffer.append('D'); 3038 break; 3039 case 'e': 3040 buffer.append('E'); 3041 break; 3042 case 'f': 3043 buffer.append('F'); 3044 break; 3045 case 'g': 3046 buffer.append('G'); 3047 break; 3048 case 'h': 3049 buffer.append('H'); 3050 break; 3051 case 'i': 3052 buffer.append('I'); 3053 break; 3054 case 'j': 3055 buffer.append('J'); 3056 break; 3057 case 'k': 3058 buffer.append('K'); 3059 break; 3060 case 'l': 3061 buffer.append('L'); 3062 break; 3063 case 'm': 3064 buffer.append('M'); 3065 break; 3066 case 'n': 3067 buffer.append('N'); 3068 break; 3069 case 'o': 3070 buffer.append('O'); 3071 break; 3072 case 'p': 3073 buffer.append('P'); 3074 break; 3075 case 'q': 3076 buffer.append('Q'); 3077 break; 3078 case 'r': 3079 buffer.append('R'); 3080 break; 3081 case 's': 3082 buffer.append('S'); 3083 break; 3084 case 't': 3085 buffer.append('T'); 3086 break; 3087 case 'u': 3088 buffer.append('U'); 3089 break; 3090 case 'v': 3091 buffer.append('V'); 3092 break; 3093 case 'w': 3094 buffer.append('W'); 3095 break; 3096 case 'x': 3097 buffer.append('X'); 3098 break; 3099 case 'y': 3100 buffer.append('Y'); 3101 break; 3102 case 'z': 3103 buffer.append('Z'); 3104 break; 3105 default: 3106 buffer.append(c); 3107 } 3108 } 3109 } 3110 3111 3112 3113 /** 3114 * Appends an uppercase string representation of the contents of the given 3115 * byte array to the provided buffer, optionally trimming leading and trailing 3116 * spaces. This implementation presumes that the provided string will contain 3117 * only ASCII characters and is optimized for that case. However, if a 3118 * non-ASCII character is encountered it will fall back on a more expensive 3119 * algorithm that will work properly for non-ASCII characters. 3120 * 3121 * @param b The byte array for which to obtain the uppercase string 3122 * representation. 3123 * @param buffer The buffer to which the uppercase form of the string should 3124 * be appended. 3125 * @param trim Indicates whether leading and trailing spaces should be 3126 * omitted from the string representation. 3127 */ 3128 public static void toUpperCase(byte[] b, StringBuilder buffer, boolean trim) 3129 { 3130 if (b == null) 3131 { 3132 return; 3133 } 3134 3135 int length = b.length; 3136 for (int i=0; i < length; i++) 3137 { 3138 if ((b[i] & 0x7F) != b[i]) 3139 { 3140 try 3141 { 3142 buffer.append(new String(b, i, (length-i), "UTF-8").toUpperCase()); 3143 } 3144 catch (Exception e) 3145 { 3146 logger.traceException(e); 3147 buffer.append(new String(b, i, (length - i)).toUpperCase()); 3148 } 3149 break; 3150 } 3151 3152 int bufferLength = buffer.length(); 3153 switch (b[i]) 3154 { 3155 case ' ': 3156 // If we don't care about trimming, then we can always append the 3157 // space. Otherwise, only do so if there are other characters in the value. 3158 if (trim && bufferLength == 0) 3159 { 3160 break; 3161 } 3162 3163 buffer.append(' '); 3164 break; 3165 case 'a': 3166 buffer.append('A'); 3167 break; 3168 case 'b': 3169 buffer.append('B'); 3170 break; 3171 case 'c': 3172 buffer.append('C'); 3173 break; 3174 case 'd': 3175 buffer.append('D'); 3176 break; 3177 case 'e': 3178 buffer.append('E'); 3179 break; 3180 case 'f': 3181 buffer.append('F'); 3182 break; 3183 case 'g': 3184 buffer.append('G'); 3185 break; 3186 case 'h': 3187 buffer.append('H'); 3188 break; 3189 case 'i': 3190 buffer.append('I'); 3191 break; 3192 case 'j': 3193 buffer.append('J'); 3194 break; 3195 case 'k': 3196 buffer.append('K'); 3197 break; 3198 case 'l': 3199 buffer.append('L'); 3200 break; 3201 case 'm': 3202 buffer.append('M'); 3203 break; 3204 case 'n': 3205 buffer.append('N'); 3206 break; 3207 case 'o': 3208 buffer.append('O'); 3209 break; 3210 case 'p': 3211 buffer.append('P'); 3212 break; 3213 case 'q': 3214 buffer.append('Q'); 3215 break; 3216 case 'r': 3217 buffer.append('R'); 3218 break; 3219 case 's': 3220 buffer.append('S'); 3221 break; 3222 case 't': 3223 buffer.append('T'); 3224 break; 3225 case 'u': 3226 buffer.append('U'); 3227 break; 3228 case 'v': 3229 buffer.append('V'); 3230 break; 3231 case 'w': 3232 buffer.append('W'); 3233 break; 3234 case 'x': 3235 buffer.append('X'); 3236 break; 3237 case 'y': 3238 buffer.append('Y'); 3239 break; 3240 case 'z': 3241 buffer.append('Z'); 3242 break; 3243 default: 3244 buffer.append((char) b[i]); 3245 } 3246 } 3247 3248 if (trim) 3249 { 3250 // Strip off any trailing spaces. 3251 for (int i=buffer.length()-1; i > 0; i--) 3252 { 3253 if (buffer.charAt(i) == ' ') 3254 { 3255 buffer.delete(i, i+1); 3256 } 3257 else 3258 { 3259 break; 3260 } 3261 } 3262 } 3263 } 3264 3265 3266 3267 /** 3268 * Append a string to a string builder, escaping any double quotes 3269 * according to the StringValue production in RFC 3641. 3270 * <p> 3271 * In RFC 3641 the StringValue production looks like this: 3272 * 3273 * <pre> 3274 * StringValue = dquote *SafeUTF8Character dquote 3275 * dquote = %x22 ; " (double quote) 3276 * SafeUTF8Character = %x00-21 / %x23-7F / ; ASCII minus dquote 3277 * dquote dquote / ; escaped double quote 3278 * %xC0-DF %x80-BF / ; 2 byte UTF-8 character 3279 * %xE0-EF 2(%x80-BF) / ; 3 byte UTF-8 character 3280 * %xF0-F7 3(%x80-BF) ; 4 byte UTF-8 character 3281 * </pre> 3282 * 3283 * <p> 3284 * That is, strings are surrounded by double-quotes and any internal 3285 * double-quotes are doubled up. 3286 * 3287 * @param builder 3288 * The string builder. 3289 * @param string 3290 * The string to escape and append. 3291 * @return Returns the string builder. 3292 */ 3293 public static StringBuilder toRFC3641StringValue(StringBuilder builder, 3294 String string) 3295 { 3296 // Initial double-quote. 3297 builder.append('"'); 3298 3299 for (char c : string.toCharArray()) 3300 { 3301 if (c == '"') 3302 { 3303 // Internal double-quotes are escaped using a double-quote. 3304 builder.append('"'); 3305 } 3306 builder.append(c); 3307 } 3308 3309 // Trailing double-quote. 3310 builder.append('"'); 3311 3312 return builder; 3313 } 3314 3315 3316 3317 /** 3318 * Retrieves a string array containing the contents of the provided 3319 * list of strings. 3320 * 3321 * @param stringList 3322 * The string list to convert to an array. 3323 * @return A string array containing the contents of the provided list 3324 * of strings. 3325 */ 3326 public static String[] listToArray(List<String> stringList) 3327 { 3328 if (stringList == null) 3329 { 3330 return null; 3331 } 3332 3333 String[] stringArray = new String[stringList.size()]; 3334 stringList.toArray(stringArray); 3335 return stringArray; 3336 } 3337 3338 /** 3339 * Retrieves an array list containing the contents of the provided array. 3340 * 3341 * @param stringArray The string array to convert to an array list. 3342 * 3343 * @return An array list containing the contents of the provided array. 3344 */ 3345 public static ArrayList<String> arrayToList(String... stringArray) 3346 { 3347 if (stringArray == null) 3348 { 3349 return null; 3350 } 3351 3352 ArrayList<String> stringList = new ArrayList<>(stringArray.length); 3353 Collections.addAll(stringList, stringArray); 3354 return stringList; 3355 } 3356 3357 3358 /** 3359 * Attempts to delete the specified file or directory. If it is a directory, 3360 * then any files or subdirectories that it contains will be recursively 3361 * deleted as well. 3362 * 3363 * @param file 3364 * The file or directory to be removed. 3365 * @return {@code true} if the specified file and any subordinates are all 3366 * successfully removed, or {@code false} if at least one element in 3367 * the subtree could not be removed or file does not exists. 3368 */ 3369 public static boolean recursiveDelete(File file) 3370 { 3371 if (file.exists()) 3372 { 3373 boolean successful = true; 3374 if (file.isDirectory()) 3375 { 3376 File[] childList = file.listFiles(); 3377 if (childList != null) 3378 { 3379 for (File f : childList) 3380 { 3381 successful &= recursiveDelete(f); 3382 } 3383 } 3384 } 3385 3386 return successful & file.delete(); 3387 } 3388 return false; 3389 } 3390 3391 3392 3393 /** 3394 * Moves the indicated file to the specified directory by creating a new file 3395 * in the target directory, copying the contents of the existing file, and 3396 * removing the existing file. The file to move must exist and must be a 3397 * file. The target directory must exist, must be a directory, and must not 3398 * be the directory in which the file currently resides. 3399 * 3400 * @param fileToMove The file to move to the target directory. 3401 * @param targetDirectory The directory into which the file should be moved. 3402 * 3403 * @throws IOException If a problem occurs while attempting to move the 3404 * file. 3405 */ 3406 public static void moveFile(File fileToMove, File targetDirectory) 3407 throws IOException 3408 { 3409 if (! fileToMove.exists()) 3410 { 3411 LocalizableMessage message = ERR_MOVEFILE_NO_SUCH_FILE.get(fileToMove.getPath()); 3412 throw new IOException(message.toString()); 3413 } 3414 3415 if (! fileToMove.isFile()) 3416 { 3417 LocalizableMessage message = ERR_MOVEFILE_NOT_FILE.get(fileToMove.getPath()); 3418 throw new IOException(message.toString()); 3419 } 3420 3421 if (! targetDirectory.exists()) 3422 { 3423 LocalizableMessage message = 3424 ERR_MOVEFILE_NO_SUCH_DIRECTORY.get(targetDirectory.getPath()); 3425 throw new IOException(message.toString()); 3426 } 3427 3428 if (! targetDirectory.isDirectory()) 3429 { 3430 LocalizableMessage message = 3431 ERR_MOVEFILE_NOT_DIRECTORY.get(targetDirectory.getPath()); 3432 throw new IOException(message.toString()); 3433 } 3434 3435 String newFilePath = targetDirectory.getPath() + File.separator + 3436 fileToMove.getName(); 3437 FileInputStream inputStream = new FileInputStream(fileToMove); 3438 FileOutputStream outputStream = new FileOutputStream(newFilePath, false); 3439 byte[] buffer = new byte[8192]; 3440 while (true) 3441 { 3442 int bytesRead = inputStream.read(buffer); 3443 if (bytesRead < 0) 3444 { 3445 break; 3446 } 3447 3448 outputStream.write(buffer, 0, bytesRead); 3449 } 3450 3451 outputStream.flush(); 3452 outputStream.close(); 3453 inputStream.close(); 3454 fileToMove.delete(); 3455 } 3456 3457 /** 3458 * Renames the source file to the target file. If the target file exists 3459 * it is first deleted. The rename and delete operation return values 3460 * are checked for success and if unsuccessful, this method throws an 3461 * exception. 3462 * 3463 * @param fileToRename The file to rename. 3464 * @param target The file to which <code>fileToRename</code> will be 3465 * moved. 3466 * @throws IOException If a problem occurs while attempting to rename the 3467 * file. On the Windows platform, this typically 3468 * indicates that the file is in use by this or another 3469 * application. 3470 */ 3471 public static void renameFile(File fileToRename, File target) 3472 throws IOException { 3473 if (fileToRename != null && target != null) 3474 { 3475 synchronized(target) 3476 { 3477 if (target.exists() && !target.delete()) 3478 { 3479 LocalizableMessage message = 3480 ERR_RENAMEFILE_CANNOT_DELETE_TARGET.get(target.getPath()); 3481 throw new IOException(message.toString()); 3482 } 3483 } 3484 if (!fileToRename.renameTo(target)) 3485 { 3486 LocalizableMessage message = ERR_RENAMEFILE_CANNOT_RENAME.get( 3487 fileToRename.getPath(), target.getPath()); 3488 throw new IOException(message.toString()); 3489 3490 } 3491 } 3492 } 3493 3494 3495 /** 3496 * Indicates whether the provided path refers to a relative path rather than 3497 * an absolute path. 3498 * 3499 * @param path The path string for which to make the determination. 3500 * 3501 * @return <CODE>true</CODE> if the provided path is relative, or 3502 * <CODE>false</CODE> if it is absolute. 3503 */ 3504 public static boolean isRelativePath(String path) 3505 { 3506 File f = new File(path); 3507 return !f.isAbsolute(); 3508 } 3509 3510 3511 3512 /** 3513 * Retrieves a <CODE>File</CODE> object corresponding to the specified path. 3514 * If the given path is an absolute path, then it will be used. If the path 3515 * is relative, then it will be interpreted as if it were relative to the 3516 * Directory Server root. 3517 * 3518 * @param path The path string to be retrieved as a <CODE>File</CODE> 3519 * 3520 * @return A <CODE>File</CODE> object that corresponds to the specified path. 3521 */ 3522 public static File getFileForPath(String path) 3523 { 3524 File f = new File (path); 3525 3526 if (f.isAbsolute()) 3527 { 3528 return f; 3529 } 3530 else 3531 { 3532 return new File(DirectoryServer.getInstanceRoot() + File.separator + 3533 path); 3534 } 3535 } 3536 3537 /** 3538 * Retrieves a <CODE>File</CODE> object corresponding to the specified path. 3539 * If the given path is an absolute path, then it will be used. If the path 3540 * is relative, then it will be interpreted as if it were relative to the 3541 * Directory Server root. 3542 * 3543 * @param path 3544 * The path string to be retrieved as a <CODE>File</CODE>. 3545 * @param serverContext 3546 * The server context. 3547 * 3548 * @return A <CODE>File</CODE> object that corresponds to the specified path. 3549 */ 3550 public static File getFileForPath(String path, ServerContext serverContext) 3551 { 3552 File f = new File (path); 3553 3554 if (f.isAbsolute()) 3555 { 3556 return f; 3557 } 3558 else 3559 { 3560 return new File(serverContext.getInstanceRoot() + File.separator + 3561 path); 3562 } 3563 } 3564 3565 3566 3567 /** 3568 * Creates a new, blank entry with the given DN. It will contain only the 3569 * attribute(s) contained in the RDN. The choice of objectclasses will be 3570 * based on the RDN attribute. If there is a single RDN attribute, then the 3571 * following mapping will be used: 3572 * <BR> 3573 * <UL> 3574 * <LI>c attribute :: country objectclass</LI> 3575 * <LI>dc attribute :: domain objectclass</LI> 3576 * <LI>o attribute :: organization objectclass</LI> 3577 * <LI>ou attribute :: organizationalUnit objectclass</LI> 3578 * </UL> 3579 * <BR> 3580 * Any other single RDN attribute types, or any case in which there are 3581 * multiple RDN attributes, will use the untypedObject objectclass. If the 3582 * RDN includes one or more attributes that are not allowed in the 3583 * untypedObject objectclass, then the extensibleObject class will also be 3584 * added. Note that this method cannot be used to generate an entry 3585 * with an empty or null DN. 3586 * 3587 * @param dn The DN to use for the entry. 3588 * 3589 * @return The entry created with the provided DN. 3590 */ 3591 public static Entry createEntry(DN dn) 3592 { 3593 // If the provided DN was null or empty, then return null because we don't 3594 // support it. 3595 if (dn == null || dn.isRootDN()) 3596 { 3597 return null; 3598 } 3599 3600 3601 // Get the information about the RDN attributes. 3602 RDN rdn = dn.rdn(); 3603 int numAVAs = rdn.getNumValues(); 3604 3605 // If there is only one RDN attribute, then see which objectclass we should use. 3606 ObjectClass structuralClass = DirectoryServer.getObjectClass(getObjectClassName(rdn, numAVAs)); 3607 3608 // Get the top and untypedObject classes to include in the entry. 3609 LinkedHashMap<ObjectClass,String> objectClasses = new LinkedHashMap<>(3); 3610 3611 objectClasses.put(DirectoryServer.getTopObjectClass(), OC_TOP); 3612 objectClasses.put(structuralClass, structuralClass.getNameOrOID()); 3613 3614 3615 // Iterate through the RDN attributes and add them to the set of user or 3616 // operational attributes. 3617 LinkedHashMap<AttributeType,List<Attribute>> userAttributes = new LinkedHashMap<>(); 3618 LinkedHashMap<AttributeType,List<Attribute>> operationalAttributes = new LinkedHashMap<>(); 3619 3620 boolean extensibleObjectAdded = false; 3621 for (int i=0; i < numAVAs; i++) 3622 { 3623 AttributeType attrType = rdn.getAttributeType(i); 3624 ByteString attrValue = rdn.getAttributeValue(i); 3625 String attrName = rdn.getAttributeName(i); 3626 3627 // First, see if this type is allowed by the untypedObject class. If not, 3628 // then we'll need to include the extensibleObject class. 3629 if (!structuralClass.isRequiredOrOptional(attrType) && !extensibleObjectAdded) 3630 { 3631 ObjectClass extensibleObjectOC = 3632 DirectoryServer.getObjectClass(OC_EXTENSIBLE_OBJECT_LC); 3633 if (extensibleObjectOC == null) 3634 { 3635 extensibleObjectOC = 3636 DirectoryServer.getDefaultObjectClass(OC_EXTENSIBLE_OBJECT); 3637 } 3638 objectClasses.put(extensibleObjectOC, OC_EXTENSIBLE_OBJECT); 3639 extensibleObjectAdded = true; 3640 } 3641 3642 3643 // Create the attribute and add it to the appropriate map. 3644 if (attrType.isOperational()) 3645 { 3646 addAttributeValue(operationalAttributes, attrType, attrName, attrValue); 3647 } 3648 else 3649 { 3650 addAttributeValue(userAttributes, attrType, attrName, attrValue); 3651 } 3652 } 3653 3654 3655 // Create and return the entry. 3656 return new Entry(dn, objectClasses, userAttributes, operationalAttributes); 3657 } 3658 3659 private static String getObjectClassName(RDN rdn, int numAVAs) 3660 { 3661 if (numAVAs == 1) 3662 { 3663 final AttributeType attrType = rdn.getAttributeType(0); 3664 if (attrType.hasName(ATTR_C)) 3665 { 3666 return OC_COUNTRY; 3667 } 3668 else if (attrType.hasName(ATTR_DC)) 3669 { 3670 return OC_DOMAIN; 3671 } 3672 else if (attrType.hasName(ATTR_O)) 3673 { 3674 return OC_ORGANIZATION; 3675 } 3676 else if (attrType.hasName(ATTR_OU)) 3677 { 3678 return OC_ORGANIZATIONAL_UNIT_LC; 3679 } 3680 } 3681 return OC_UNTYPED_OBJECT_LC; 3682 } 3683 3684 private static void addAttributeValue(LinkedHashMap<AttributeType, List<Attribute>> attrs, 3685 AttributeType attrType, String attrName, ByteString attrValue) 3686 { 3687 List<Attribute> attrList = attrs.get(attrType); 3688 if (attrList != null && !attrList.isEmpty()) 3689 { 3690 AttributeBuilder builder = new AttributeBuilder(attrList.get(0)); 3691 builder.add(attrValue); 3692 attrList.set(0, builder.toAttribute()); 3693 } 3694 else 3695 { 3696 AttributeBuilder builder = new AttributeBuilder(attrType, attrName); 3697 builder.add(attrValue); 3698 attrs.put(attrType, builder.toAttributeList()); 3699 } 3700 } 3701 3702 /** 3703 * Retrieves a user-friendly string that indicates the length of time (in 3704 * days, hours, minutes, and seconds) in the specified number of seconds. 3705 * 3706 * @param numSeconds The number of seconds to be converted to a more 3707 * user-friendly value. 3708 * 3709 * @return The user-friendly representation of the specified number of 3710 * seconds. 3711 */ 3712 public static LocalizableMessage secondsToTimeString(long numSeconds) 3713 { 3714 if (numSeconds < 60) 3715 { 3716 // We can express it in seconds. 3717 return INFO_TIME_IN_SECONDS.get(numSeconds); 3718 } 3719 else if (numSeconds < 3600) 3720 { 3721 // We can express it in minutes and seconds. 3722 long m = numSeconds / 60; 3723 long s = numSeconds % 60; 3724 return INFO_TIME_IN_MINUTES_SECONDS.get(m, s); 3725 } 3726 else if (numSeconds < 86400) 3727 { 3728 // We can express it in hours, minutes, and seconds. 3729 long h = numSeconds / 3600; 3730 long m = (numSeconds % 3600) / 60; 3731 long s = numSeconds % 3600 % 60; 3732 return INFO_TIME_IN_HOURS_MINUTES_SECONDS.get(h, m, s); 3733 } 3734 else 3735 { 3736 // We can express it in days, hours, minutes, and seconds. 3737 long d = numSeconds / 86400; 3738 long h = (numSeconds % 86400) / 3600; 3739 long m = (numSeconds % 86400 % 3600) / 60; 3740 long s = numSeconds % 86400 % 3600 % 60; 3741 return INFO_TIME_IN_DAYS_HOURS_MINUTES_SECONDS.get(d, h, m, s); 3742 } 3743 } 3744 3745 /** 3746 * Checks that no more that one of a set of arguments is present. This 3747 * utility should be used after argument parser has parsed a set of 3748 * arguments. 3749 * 3750 * @param args to test for the presence of more than one 3751 * @throws ArgumentException if more than one of <code>args</code> is 3752 * present and containing an error message identifying the 3753 * arguments in violation 3754 */ 3755 public static void checkOnlyOneArgPresent(Argument... args) 3756 throws ArgumentException 3757 { 3758 if (args != null) { 3759 for (Argument arg : args) { 3760 for (Argument otherArg : args) { 3761 if (arg != otherArg && arg.isPresent() && otherArg.isPresent()) { 3762 throw new ArgumentException( 3763 ToolMessages.ERR_INCOMPATIBLE_ARGUMENTS.get( 3764 arg.getName(), otherArg.getName())); 3765 } 3766 } 3767 } 3768 } 3769 } 3770 3771 /** 3772 * Converts a string representing a time in "yyyyMMddHHmmss.SSS'Z'" or 3773 * "yyyyMMddHHmmss" to a <code>Date</code>. 3774 * 3775 * @param timeStr string formatted appropriately 3776 * @return Date object; null if <code>timeStr</code> is null 3777 * @throws ParseException if there was a problem converting the string to 3778 * a <code>Date</code>. 3779 */ 3780 public static Date parseDateTimeString(String timeStr) throws ParseException 3781 { 3782 Date dateTime = null; 3783 if (timeStr != null) 3784 { 3785 if (timeStr.endsWith("Z")) 3786 { 3787 try 3788 { 3789 SimpleDateFormat dateFormat = 3790 new SimpleDateFormat(DATE_FORMAT_GENERALIZED_TIME); 3791 dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); 3792 dateFormat.setLenient(true); 3793 dateTime = dateFormat.parse(timeStr); 3794 } 3795 catch (ParseException pe) 3796 { 3797 // Best effort: try with GMT time. 3798 SimpleDateFormat dateFormat = 3799 new SimpleDateFormat(DATE_FORMAT_GMT_TIME); 3800 dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); 3801 dateFormat.setLenient(true); 3802 dateTime = dateFormat.parse(timeStr); 3803 } 3804 } 3805 else 3806 { 3807 SimpleDateFormat dateFormat = 3808 new SimpleDateFormat(DATE_FORMAT_COMPACT_LOCAL_TIME); 3809 dateFormat.setLenient(true); 3810 dateTime = dateFormat.parse(timeStr); 3811 } 3812 } 3813 return dateTime; 3814 } 3815 3816 /** 3817 * Formats a Date to String representation in "yyyyMMddHHmmss'Z'". 3818 * 3819 * @param date to format; null if <code>date</code> is null 3820 * @return string representation of the date 3821 */ 3822 public static String formatDateTimeString(Date date) 3823 { 3824 String timeStr = null; 3825 if (date != null) 3826 { 3827 SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_GMT_TIME); 3828 dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); 3829 timeStr = dateFormat.format(date); 3830 } 3831 return timeStr; 3832 } 3833 3834 /** 3835 * Indicates whether or not a string represents a syntactically correct 3836 * email address. 3837 * 3838 * @param addr to validate 3839 * @return boolean where <code>true</code> indicates that the string is a 3840 * syntactically correct email address 3841 */ 3842 public static boolean isEmailAddress(String addr) { 3843 3844 // This just does basic syntax checking. Perhaps we 3845 // might want to be stricter about this. 3846 return addr != null && addr.contains("@") && addr.contains("."); 3847 3848 } 3849 3850 3851 3852 /** 3853 * Writes the contents of the provided buffer to the client, 3854 * terminating the connection if the write is unsuccessful for too 3855 * long (e.g., if the client is unresponsive or there is a network 3856 * problem). If possible, it will attempt to use the selector returned 3857 * by the {@code ClientConnection.getWriteSelector} method, but it is 3858 * capable of working even if that method returns {@code null}. <BR> 3859 * 3860 * Note that the original position and limit values will not be 3861 * preserved, so if that is important to the caller, then it should 3862 * record them before calling this method and restore them after it 3863 * returns. 3864 * 3865 * @param clientConnection 3866 * The client connection to which the data is to be written. 3867 * @param buffer 3868 * The data to be written to the client. 3869 * @return <CODE>true</CODE> if all the data in the provided buffer was 3870 * written to the client and the connection may remain 3871 * established, or <CODE>false</CODE> if a problem occurred 3872 * and the client connection is no longer valid. Note that if 3873 * this method does return <CODE>false</CODE>, then it must 3874 * have already disconnected the client. 3875 * @throws IOException 3876 * If a problem occurs while attempting to write data to the 3877 * client. The caller will be responsible for catching this 3878 * and terminating the client connection. 3879 */ 3880 public static boolean writeWithTimeout(ClientConnection clientConnection, 3881 ByteBuffer buffer) throws IOException 3882 { 3883 SocketChannel socketChannel = clientConnection.getSocketChannel(); 3884 long startTime = System.currentTimeMillis(); 3885 long waitTime = clientConnection.getMaxBlockedWriteTimeLimit(); 3886 if (waitTime <= 0) 3887 { 3888 // We won't support an infinite time limit, so fall back to using 3889 // five minutes, which is a very long timeout given that we're 3890 // blocking a worker thread. 3891 waitTime = 300000L; 3892 } 3893 3894 long stopTime = startTime + waitTime; 3895 3896 Selector selector = clientConnection.getWriteSelector(); 3897 if (selector == null) 3898 { 3899 // The client connection does not provide a selector, so we'll 3900 // fall back 3901 // to a more inefficient way that will work without a selector. 3902 while (buffer.hasRemaining() 3903 && System.currentTimeMillis() < stopTime) 3904 { 3905 if (socketChannel.write(buffer) < 0) 3906 { 3907 // The client connection has been closed. 3908 return false; 3909 } 3910 } 3911 3912 if (buffer.hasRemaining()) 3913 { 3914 // If we've gotten here, then the write timed out. 3915 return false; 3916 } 3917 3918 return true; 3919 } 3920 3921 // Register with the selector for handling write operations. 3922 SelectionKey key = 3923 socketChannel.register(selector, SelectionKey.OP_WRITE); 3924 3925 try 3926 { 3927 selector.select(waitTime); 3928 while (buffer.hasRemaining()) 3929 { 3930 long currentTime = System.currentTimeMillis(); 3931 if (currentTime >= stopTime) 3932 { 3933 // We've been blocked for too long. 3934 return false; 3935 } 3936 else 3937 { 3938 waitTime = stopTime - currentTime; 3939 } 3940 3941 Iterator<SelectionKey> iterator = 3942 selector.selectedKeys().iterator(); 3943 while (iterator.hasNext()) 3944 { 3945 SelectionKey k = iterator.next(); 3946 if (k.isWritable()) 3947 { 3948 int bytesWritten = socketChannel.write(buffer); 3949 if (bytesWritten < 0) 3950 { 3951 // The client connection has been closed. 3952 return false; 3953 } 3954 3955 iterator.remove(); 3956 } 3957 } 3958 3959 if (buffer.hasRemaining()) 3960 { 3961 selector.select(waitTime); 3962 } 3963 } 3964 3965 return true; 3966 } 3967 finally 3968 { 3969 if (key.isValid()) 3970 { 3971 key.cancel(); 3972 selector.selectNow(); 3973 } 3974 } 3975 } 3976 3977 3978 3979 /** 3980 * Add all of the superior objectclasses to the specified objectclass 3981 * map if they don't already exist. Used by add and import-ldif to 3982 * add missing superior objectclasses to entries that don't have them. 3983 * 3984 * @param objectClasses A Map of objectclasses. 3985 */ 3986 public static void addSuperiorObjectClasses(Map<ObjectClass, 3987 String> objectClasses) { 3988 HashSet<ObjectClass> additionalClasses = null; 3989 for (ObjectClass oc : objectClasses.keySet()) 3990 { 3991 for(ObjectClass superiorClass : oc.getSuperiorClasses()) 3992 { 3993 if (! objectClasses.containsKey(superiorClass)) 3994 { 3995 if (additionalClasses == null) 3996 { 3997 additionalClasses = new HashSet<>(); 3998 } 3999 4000 additionalClasses.add(superiorClass); 4001 } 4002 } 4003 } 4004 4005 if (additionalClasses != null) 4006 { 4007 for (ObjectClass oc : additionalClasses) 4008 { 4009 addObjectClassChain(oc, objectClasses); 4010 } 4011 } 4012 } 4013 4014 private static void addObjectClassChain(ObjectClass objectClass, 4015 Map<ObjectClass, String> objectClasses) 4016 { 4017 if (objectClasses != null){ 4018 if (! objectClasses.containsKey(objectClass)) 4019 { 4020 objectClasses.put(objectClass, objectClass.getNameOrOID()); 4021 } 4022 4023 for(ObjectClass superiorClass : objectClass.getSuperiorClasses()) 4024 { 4025 if (! objectClasses.containsKey(superiorClass)) 4026 { 4027 addObjectClassChain(superiorClass, objectClasses); 4028 } 4029 } 4030 } 4031 } 4032 4033 4034 /** 4035 * Closes the provided {@link Closeable}'s ignoring any errors which 4036 * occurred. 4037 * 4038 * @param closeables The closeables to be closed, which may be 4039 * <code>null</code>. 4040 */ 4041 public static void close(Closeable... closeables) 4042 { 4043 if (closeables == null) 4044 { 4045 return; 4046 } 4047 close(Arrays.asList(closeables)); 4048 } 4049 4050 /** 4051 * Closes the provided {@link Closeable}'s ignoring any errors which occurred. 4052 * 4053 * @param closeables 4054 * The closeables to be closed, which may be <code>null</code>. 4055 */ 4056 public static void close(Collection<? extends Closeable> closeables) 4057 { 4058 if (closeables == null) 4059 { 4060 return; 4061 } 4062 for (Closeable closeable : closeables) 4063 { 4064 if (closeable != null) 4065 { 4066 try 4067 { 4068 closeable.close(); 4069 } 4070 catch (IOException ignored) 4071 { 4072 logger.traceException(ignored); 4073 } 4074 } 4075 } 4076 } 4077 4078 /** 4079 * Closes the provided {@link InitialContext}s ignoring any errors which occurred. 4080 * 4081 * @param ctxs 4082 * The contexts to be closed, which may be <code>null</code>. 4083 */ 4084 public static void close(InitialContext... ctxs) 4085 { 4086 if (ctxs == null) 4087 { 4088 return; 4089 } 4090 for (InitialContext ctx : ctxs) 4091 { 4092 if (ctx != null) 4093 { 4094 try 4095 { 4096 ctx.close(); 4097 } 4098 catch (NamingException ignored) 4099 { 4100 // ignore 4101 } 4102 } 4103 } 4104 } 4105 4106 /** 4107 * Calls {@link Thread#sleep(long)}, surrounding it with the mandatory 4108 * <code>try</code> / <code>catch(InterruptedException)</code> block. 4109 * 4110 * @param millis 4111 * the length of time to sleep in milliseconds 4112 */ 4113 public static void sleep(long millis) 4114 { 4115 try 4116 { 4117 Thread.sleep(millis); 4118 } 4119 catch (InterruptedException wokenUp) 4120 { 4121 // ignore 4122 } 4123 } 4124 4125 /** 4126 * Test if the provided message corresponds to the provided descriptor. 4127 * 4128 * @param msg 4129 * The i18n message. 4130 * @param desc 4131 * The message descriptor. 4132 * @return {@code true} if message corresponds to descriptor 4133 */ 4134 public static boolean hasDescriptor(LocalizableMessage msg, 4135 LocalizableMessageDescriptor.Arg0 desc) 4136 { 4137 return msg.ordinal() == desc.ordinal() 4138 && msg.resourceName().equals(desc.resourceName()); 4139 } 4140 4141 /** 4142 * Test if the provided message corresponds to the provided descriptor. 4143 * 4144 * @param msg 4145 * The i18n message. 4146 * @param desc 4147 * The message descriptor. 4148 * @return {@code true} if message corresponds to descriptor 4149 */ 4150 public static boolean hasDescriptor(LocalizableMessage msg, 4151 LocalizableMessageDescriptor.Arg1 desc) 4152 { 4153 return msg.ordinal() == desc.ordinal() 4154 && msg.resourceName().equals(desc.resourceName()); 4155 } 4156 4157 /** 4158 * Test if the provided message corresponds to the provided descriptor. 4159 * 4160 * @param msg 4161 * The i18n message. 4162 * @param desc 4163 * The message descriptor. 4164 * @return {@code true} if message corresponds to descriptor 4165 */ 4166 public static boolean hasDescriptor(LocalizableMessage msg, 4167 LocalizableMessageDescriptor.Arg2 desc) 4168 { 4169 return msg.ordinal() == desc.ordinal() 4170 && msg.resourceName().equals(desc.resourceName()); 4171 } 4172 4173 /** 4174 * Test if the provided message corresponds to the provided descriptor. 4175 * 4176 * @param msg 4177 * The i18n message. 4178 * @param desc 4179 * The message descriptor. 4180 * @return {@code true} if message corresponds to descriptor 4181 */ 4182 public static boolean hasDescriptor(LocalizableMessage msg, 4183 LocalizableMessageDescriptor.Arg3 desc) 4184 { 4185 return msg.ordinal() == desc.ordinal() 4186 && msg.resourceName().equals(desc.resourceName()); 4187 } 4188 4189 /** 4190 * Test if the provided message corresponds to the provided descriptor. 4191 * 4192 * @param msg 4193 * The i18n message. 4194 * @param desc 4195 * The message descriptor. 4196 * @return {@code true} if message corresponds to descriptor 4197 */ 4198 public static boolean hasDescriptor(LocalizableMessage msg, 4199 LocalizableMessageDescriptor.Arg7 desc) 4200 { 4201 return msg.ordinal() == desc.ordinal() 4202 && msg.resourceName().equals(desc.resourceName()); 4203 } 4204 4205 /** 4206 * Returns an {@link Iterable} returning the passed in {@link Iterator}. THis 4207 * allows using methods returning Iterators with foreach statements. 4208 * <p> 4209 * For example, consider a method with this signature: 4210 * <p> 4211 * <code>public Iterator<String> myIteratorMethod();</code> 4212 * <p> 4213 * Classical use with for or while loop: 4214 * 4215 * <pre> 4216 * for (Iterator<String> it = myIteratorMethod(); it.hasNext();) 4217 * { 4218 * String s = it.next(); 4219 * // use it 4220 * } 4221 * 4222 * Iterator<String> it = myIteratorMethod(); 4223 * while(it.hasNext();) 4224 * { 4225 * String s = it.next(); 4226 * // use it 4227 * } 4228 * </pre> 4229 * 4230 * Improved use with foreach: 4231 * 4232 * <pre> 4233 * for (String s : StaticUtils.toIterable(myIteratorMethod())) 4234 * { 4235 * } 4236 * </pre> 4237 * 4238 * </p> 4239 * 4240 * @param <T> 4241 * the generic type of the passed in Iterator and for the returned 4242 * Iterable. 4243 * @param iterator 4244 * the Iterator that will be returned by the Iterable. 4245 * @return an Iterable returning the passed in Iterator 4246 */ 4247 public static <T> Iterable<T> toIterable(final Iterator<T> iterator) 4248 { 4249 return new Iterable<T>() 4250 { 4251 @Override 4252 public Iterator<T> iterator() 4253 { 4254 return iterator; 4255 } 4256 }; 4257 } 4258} 4259