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