001/* 002 * Copyright 2008-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2017 UnboundID Corp. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.util; 022 023 024 025import java.io.Serializable; 026import java.util.EnumSet; 027import java.util.Properties; 028import java.util.Set; 029import java.util.StringTokenizer; 030import java.util.logging.Level; 031import java.util.logging.Logger; 032 033import com.unboundid.asn1.ASN1Buffer; 034import com.unboundid.asn1.ASN1Element; 035import com.unboundid.ldap.protocol.LDAPResponse; 036import com.unboundid.ldap.sdk.DisconnectType; 037import com.unboundid.ldap.sdk.Entry; 038import com.unboundid.ldap.sdk.LDAPConnection; 039import com.unboundid.ldap.sdk.LDAPRequest; 040import com.unboundid.ldap.sdk.Version; 041import com.unboundid.ldif.LDIFRecord; 042 043import static com.unboundid.util.StaticUtils.*; 044 045 046 047/** 048 * This class provides a means of enabling and configuring debugging in the LDAP 049 * SDK. 050 * <BR><BR> 051 * Access to debug information can be enabled through applications that use the 052 * SDK by calling the {@link Debug#setEnabled} methods, or it can also be 053 * enabled without any code changes through the use of system properties. In 054 * particular, the {@link Debug#PROPERTY_DEBUG_ENABLED}, 055 * {@link Debug#PROPERTY_DEBUG_LEVEL}, and {@link Debug#PROPERTY_DEBUG_TYPE} 056 * properties may be used to control debugging without the need to alter any 057 * code within the application that uses the SDK. 058 * <BR><BR> 059 * The LDAP SDK debugging subsystem uses the Java logging framework available 060 * through the {@code java.util.logging} package with a logger name of 061 * "{@code com.unboundid.ldap.sdk}". The {@link Debug#getLogger} method may 062 * be used to access the logger instance used by the LDAP SDK. 063 * <BR><BR> 064 * <H2>Example</H2> 065 * The following example demonstrates the process that may be used to enable 066 * debugging within the LDAP SDK and write information about all messages with 067 * a {@code WARNING} level or higher to a specified file: 068 * <PRE> 069 * Debug.setEnabled(true); 070 * Logger logger = Debug.getLogger(); 071 * 072 * FileHandler fileHandler = new FileHandler(logFilePath); 073 * fileHandler.setLevel(Level.WARNING); 074 * logger.addHandler(fileHandler); 075 * </PRE> 076 */ 077@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 078public final class Debug 079 implements Serializable 080{ 081 /** 082 * The name of the system property that will be used to enable debugging in 083 * the UnboundID LDAP SDK for Java. The fully-qualified name for this 084 * property is "{@code com.unboundid.ldap.sdk.debug.enabled}". If it is set, 085 * then it should have a value of either "true" or "false". 086 */ 087 public static final String PROPERTY_DEBUG_ENABLED = 088 "com.unboundid.ldap.sdk.debug.enabled"; 089 090 091 092 /** 093 * The name of the system property that may be used to indicate whether stack 094 * trace information for the thread calling the debug method should be 095 * included in debug log messages. The fully-qualified name for this property 096 * is "{@code com.unboundid.ldap.sdk.debug.includeStackTrace}". If it is set, 097 * then it should have a value of either "true" or "false". 098 */ 099 public static final String PROPERTY_INCLUDE_STACK_TRACE = 100 "com.unboundid.ldap.sdk.debug.includeStackTrace"; 101 102 103 104 /** 105 * The name of the system property that will be used to set the initial level 106 * for the debug logger. The fully-qualified name for this property is 107 * "{@code com.unboundid.ldap.sdk.debug.level}". If it is set, then it should 108 * be one of the strings "{@code SEVERE}", "{@code WARNING}", "{@code INFO}", 109 * "{@code CONFIG}", "{@code FINE}", "{@code FINER}", or "{@code FINEST}". 110 */ 111 public static final String PROPERTY_DEBUG_LEVEL = 112 "com.unboundid.ldap.sdk.debug.level"; 113 114 115 116 /** 117 * The name of the system property that will be used to indicate that 118 * debugging should be enabled for specific types of messages. The 119 * fully-qualified name for this property is 120 * "{@code com.unboundid.ldap.sdk.debug.type}". If it is set, then it should 121 * be a comma-delimited list of the names of the desired debug types. See the 122 * {@link DebugType} enum for the available debug types. 123 */ 124 public static final String PROPERTY_DEBUG_TYPE = 125 "com.unboundid.ldap.sdk.debug.type"; 126 127 128 129 /** 130 * The name that will be used for the Java logger that will actually handle 131 * the debug messages if debugging is enabled. 132 */ 133 public static final String LOGGER_NAME = "com.unboundid.ldap.sdk"; 134 135 136 137 /** 138 * The logger that will be used to handle the debug messages if debugging is 139 * enabled. 140 */ 141 private static final Logger logger = Logger.getLogger(LOGGER_NAME); 142 143 144 145 /** 146 * The serial version UID for this serializable class. 147 */ 148 private static final long serialVersionUID = -6079754380415146030L; 149 150 151 152 // Indicates whether any debugging is currently enabled for the SDK. 153 private static boolean debugEnabled; 154 155 // Indicates whether to capture a thread stack trace whenever a debug message 156 // is logged. 157 private static boolean includeStackTrace; 158 159 // The set of debug types for which debugging is enabled. 160 private static EnumSet<DebugType> debugTypes; 161 162 163 164 static 165 { 166 initialize(System.getProperties()); 167 } 168 169 170 171 /** 172 * Prevent this class from being instantiated. 173 */ 174 private Debug() 175 { 176 // No implementation is required. 177 } 178 179 180 181 /** 182 * Initializes this debugger with the default settings. Debugging will be 183 * disabled, the set of debug types will include all types, and the debug 184 * level will be "ALL". 185 */ 186 public static void initialize() 187 { 188 includeStackTrace = false; 189 debugEnabled = false; 190 debugTypes = EnumSet.allOf(DebugType.class); 191 192 logger.setLevel(Level.ALL); 193 } 194 195 196 197 /** 198 * Initializes this debugger with settings from the provided set of 199 * properties. Any debug setting that isn't configured in the provided 200 * properties will be initialized with its default value. 201 * 202 * @param properties The set of properties to use to initialize this 203 * debugger. 204 */ 205 public static void initialize(final Properties properties) 206 { 207 // First, apply the default values for the properties. 208 initialize(); 209 if ((properties == null) || properties.isEmpty()) 210 { 211 // No properties were provided, so we don't need to do anything. 212 return; 213 } 214 215 final String enabledProp = properties.getProperty(PROPERTY_DEBUG_ENABLED); 216 if ((enabledProp != null) && (enabledProp.length() > 0)) 217 { 218 if (enabledProp.equalsIgnoreCase("true")) 219 { 220 debugEnabled = true; 221 } 222 else if (enabledProp.equalsIgnoreCase("false")) 223 { 224 debugEnabled = false; 225 } 226 else 227 { 228 throw new IllegalArgumentException("Invalid value '" + enabledProp + 229 "' for property " + 230 PROPERTY_DEBUG_ENABLED + 231 ". The value must be either " + 232 "'true' or 'false'."); 233 } 234 } 235 236 final String stackProp = 237 properties.getProperty(PROPERTY_INCLUDE_STACK_TRACE); 238 if ((stackProp != null) && (stackProp.length() > 0)) 239 { 240 if (stackProp.equalsIgnoreCase("true")) 241 { 242 includeStackTrace = true; 243 } 244 else if (stackProp.equalsIgnoreCase("false")) 245 { 246 includeStackTrace = false; 247 } 248 else 249 { 250 throw new IllegalArgumentException("Invalid value '" + stackProp + 251 "' for property " + 252 PROPERTY_INCLUDE_STACK_TRACE + 253 ". The value must be either " + 254 "'true' or 'false'."); 255 } 256 } 257 258 final String typesProp = properties.getProperty(PROPERTY_DEBUG_TYPE); 259 if ((typesProp != null) && (typesProp.length() > 0)) 260 { 261 debugTypes = EnumSet.noneOf(DebugType.class); 262 final StringTokenizer t = new StringTokenizer(typesProp, ", "); 263 while (t.hasMoreTokens()) 264 { 265 final String debugTypeName = t.nextToken(); 266 final DebugType debugType = DebugType.forName(debugTypeName); 267 if (debugType == null) 268 { 269 // Throw a runtime exception to indicate that the debug type is 270 // invalid. 271 throw new IllegalArgumentException("Invalid value '" + debugTypeName + 272 "' for property " + PROPERTY_DEBUG_TYPE + 273 ". Allowed values include: " + 274 DebugType.getTypeNameList() + '.'); 275 } 276 else 277 { 278 debugTypes.add(debugType); 279 } 280 } 281 } 282 283 final String levelProp = properties.getProperty(PROPERTY_DEBUG_LEVEL); 284 if ((levelProp != null) && (levelProp.length() > 0)) 285 { 286 logger.setLevel(Level.parse(levelProp)); 287 } 288 } 289 290 291 292 /** 293 * Retrieves the logger that will be used to write the debug messages. 294 * 295 * @return The logger that will be used to write the debug messages. 296 */ 297 public static Logger getLogger() 298 { 299 return logger; 300 } 301 302 303 304 /** 305 * Indicates whether any form of debugging is enabled. 306 * 307 * @return {@code true} if debugging is enabled, or {@code false} if not. 308 */ 309 public static boolean debugEnabled() 310 { 311 return debugEnabled; 312 } 313 314 315 316 /** 317 * Indicates whether debugging is enabled for messages of the specified debug 318 * type. 319 * 320 * @param debugType The debug type for which to make the determination. 321 * 322 * @return {@code true} if debugging is enabled for messages of the specified 323 * debug type, or {@code false} if not. 324 */ 325 public static boolean debugEnabled(final DebugType debugType) 326 { 327 return (debugEnabled && debugTypes.contains(debugType)); 328 } 329 330 331 332 /** 333 * Specifies whether debugging should be enabled. If it should be, then it 334 * will be enabled for all debug types. 335 * 336 * @param enabled Specifies whether debugging should be enabled. 337 */ 338 public static void setEnabled(final boolean enabled) 339 { 340 debugTypes = EnumSet.allOf(DebugType.class); 341 debugEnabled = enabled; 342 } 343 344 345 346 /** 347 * Specifies whether debugging should be enabled. If it should be, then it 348 * will be enabled for all debug types in the provided set. 349 * 350 * @param enabled Specifies whether debugging should be enabled. 351 * @param types The set of debug types that should be enabled. It may be 352 * {@code null} or empty to indicate that it should be for 353 * all debug types. 354 */ 355 public static void setEnabled(final boolean enabled, 356 final Set<DebugType> types) 357 { 358 if ((types == null) || types.isEmpty()) 359 { 360 debugTypes = EnumSet.allOf(DebugType.class); 361 } 362 else 363 { 364 debugTypes = EnumSet.copyOf(types); 365 } 366 367 debugEnabled = enabled; 368 } 369 370 371 372 /** 373 * Indicates whether log messages should include a stack trace of the thread 374 * that invoked the debug method. 375 * 376 * @return {@code true} if log messages should include a stack trace of the 377 * thread that invoked the debug method, or {@code false} if not. 378 */ 379 public static boolean includeStackTrace() 380 { 381 return includeStackTrace; 382 } 383 384 385 386 /** 387 * Specifies whether log messages should include a stack trace of the thread 388 * that invoked the debug method. 389 * 390 * @param includeStackTrace Indicates whether log messages should include a 391 * stack trace of the thread that invoked the debug 392 * method. 393 */ 394 public static void setIncludeStackTrace(final boolean includeStackTrace) 395 { 396 Debug.includeStackTrace = includeStackTrace; 397 } 398 399 400 401 /** 402 * Retrieves the set of debug types that will be used if debugging is enabled. 403 * 404 * @return The set of debug types that will be used if debugging is enabled. 405 */ 406 public static EnumSet<DebugType> getDebugTypes() 407 { 408 return debugTypes; 409 } 410 411 412 413 /** 414 * Writes debug information about the provided exception, if appropriate. If 415 * it is to be logged, then it will be sent to the underlying logger using the 416 * {@code WARNING} level. 417 * 418 * @param t The exception for which debug information should be written. 419 */ 420 public static void debugException(final Throwable t) 421 { 422 if (debugEnabled && debugTypes.contains(DebugType.EXCEPTION)) 423 { 424 debugException(Level.WARNING, t); 425 } 426 } 427 428 429 430 /** 431 * Writes debug information about the provided exception, if appropriate. 432 * 433 * @param l The log level that should be used for the debug information. 434 * @param t The exception for which debug information should be written. 435 */ 436 public static void debugException(final Level l, final Throwable t) 437 { 438 if (debugEnabled && debugTypes.contains(DebugType.EXCEPTION)) 439 { 440 final StringBuilder buffer = new StringBuilder(); 441 addCommonHeader(buffer, l); 442 buffer.append("caughtException=\""); 443 getStackTrace(t, buffer); 444 buffer.append('"'); 445 446 logger.log(l, buffer.toString(), t); 447 } 448 } 449 450 451 452 /** 453 * Writes debug information to indicate that a connection has been 454 * established, if appropriate. If it is to be logged, then it will be sent 455 * to the underlying logger using the {@code INFO} level. 456 * 457 * @param h The address of the server to which the connection was 458 * established. 459 * @param p The port of the server to which the connection was established. 460 */ 461 public static void debugConnect(final String h, final int p) 462 { 463 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 464 { 465 debugConnect(Level.INFO, h, p, null); 466 } 467 } 468 469 470 471 /** 472 * Writes debug information to indicate that a connection has been 473 * established, if appropriate. 474 * 475 * @param l The log level that should be used for the debug information. 476 * @param h The address of the server to which the connection was 477 * established. 478 * @param p The port of the server to which the connection was established. 479 */ 480 public static void debugConnect(final Level l, final String h, final int p) 481 { 482 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 483 { 484 debugConnect(l, h, p, null); 485 } 486 } 487 488 489 490 /** 491 * Writes debug information to indicate that a connection has been 492 * established, if appropriate. If it is to be logged, then it will be sent 493 * to the underlying logger using the {@code INFO} level. 494 * 495 * @param h The address of the server to which the connection was 496 * established. 497 * @param p The port of the server to which the connection was established. 498 * @param c The connection object for the connection that has been 499 * established. It may be {@code null} for historic reasons, but 500 * should be non-{@code null} in new uses. 501 */ 502 public static void debugConnect(final String h, final int p, 503 final LDAPConnection c) 504 { 505 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 506 { 507 debugConnect(Level.INFO, h, p, c); 508 } 509 } 510 511 512 513 /** 514 * Writes debug information to indicate that a connection has been 515 * established, if appropriate. 516 * 517 * @param l The log level that should be used for the debug information. 518 * @param h The address of the server to which the connection was 519 * established. 520 * @param p The port of the server to which the connection was established. 521 * @param c The connection object for the connection that has been 522 * established. It may be {@code null} for historic reasons, but 523 * should be non-{@code null} in new uses. 524 */ 525 public static void debugConnect(final Level l, final String h, final int p, 526 final LDAPConnection c) 527 { 528 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 529 { 530 final StringBuilder buffer = new StringBuilder(); 531 addCommonHeader(buffer, l); 532 buffer.append("connectedTo=\""); 533 buffer.append(h); 534 buffer.append(':'); 535 buffer.append(p); 536 buffer.append('"'); 537 538 if (c != null) 539 { 540 buffer.append(" connectionID="); 541 buffer.append(c.getConnectionID()); 542 543 final String connectionName = c.getConnectionName(); 544 if (connectionName != null) 545 { 546 buffer.append(" connectionName=\""); 547 buffer.append(connectionName); 548 buffer.append('"'); 549 } 550 551 final String connectionPoolName = c.getConnectionPoolName(); 552 if (connectionPoolName != null) 553 { 554 buffer.append(" connectionPoolName=\""); 555 buffer.append(connectionPoolName); 556 buffer.append('"'); 557 } 558 } 559 560 logger.log(l, buffer.toString()); 561 } 562 } 563 564 565 566 /** 567 * Writes debug information to indicate that a connection has been 568 * terminated, if appropriate. If it is to be logged, then it will be sent 569 * to the underlying logger using the {@code INFO} level. 570 * 571 * @param h The address of the server to which the connection was 572 * established. 573 * @param p The port of the server to which the connection was established. 574 * @param t The disconnect type. 575 * @param m The disconnect message, if available. 576 * @param e The disconnect cause, if available. 577 */ 578 public static void debugDisconnect(final String h, final int p, 579 final DisconnectType t, final String m, 580 final Throwable e) 581 { 582 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 583 { 584 debugDisconnect(Level.INFO, h, p, null, t, m, e); 585 } 586 } 587 588 589 590 /** 591 * Writes debug information to indicate that a connection has been 592 * terminated, if appropriate. 593 * 594 * @param l The log level that should be used for the debug information. 595 * @param h The address of the server to which the connection was 596 * established. 597 * @param p The port of the server to which the connection was established. 598 * @param t The disconnect type. 599 * @param m The disconnect message, if available. 600 * @param e The disconnect cause, if available. 601 */ 602 public static void debugDisconnect(final Level l, final String h, final int p, 603 final DisconnectType t, final String m, 604 final Throwable e) 605 { 606 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 607 { 608 debugDisconnect(l, h, p, null, t, m, e); 609 } 610 } 611 612 613 614 /** 615 * Writes debug information to indicate that a connection has been 616 * terminated, if appropriate. If it is to be logged, then it will be sent 617 * to the underlying logger using the {@code INFO} level. 618 * 619 * @param h The address of the server to which the connection was 620 * established. 621 * @param p The port of the server to which the connection was established. 622 * @param c The connection object for the connection that has been closed. 623 * It may be {@code null} for historic reasons, but should be 624 * non-{@code null} in new uses. 625 * @param t The disconnect type. 626 * @param m The disconnect message, if available. 627 * @param e The disconnect cause, if available. 628 */ 629 public static void debugDisconnect(final String h, final int p, 630 final LDAPConnection c, 631 final DisconnectType t, final String m, 632 final Throwable e) 633 { 634 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 635 { 636 debugDisconnect(Level.INFO, h, p, c, t, m, e); 637 } 638 } 639 640 641 642 /** 643 * Writes debug information to indicate that a connection has been 644 * terminated, if appropriate. 645 * 646 * @param l The log level that should be used for the debug information. 647 * @param h The address of the server to which the connection was 648 * established. 649 * @param p The port of the server to which the connection was established. 650 * @param c The connection object for the connection that has been closed. 651 * It may be {@code null} for historic reasons, but should be 652 * non-{@code null} in new uses. 653 * @param t The disconnect type. 654 * @param m The disconnect message, if available. 655 * @param e The disconnect cause, if available. 656 */ 657 public static void debugDisconnect(final Level l, final String h, final int p, 658 final LDAPConnection c, 659 final DisconnectType t, final String m, 660 final Throwable e) 661 { 662 if (debugEnabled && debugTypes.contains(DebugType.CONNECT)) 663 { 664 final StringBuilder buffer = new StringBuilder(); 665 addCommonHeader(buffer, l); 666 667 if (c != null) 668 { 669 buffer.append("connectionID="); 670 buffer.append(c.getConnectionID()); 671 672 final String connectionName = c.getConnectionName(); 673 if (connectionName != null) 674 { 675 buffer.append(" connectionName=\""); 676 buffer.append(connectionName); 677 buffer.append('"'); 678 } 679 680 final String connectionPoolName = c.getConnectionPoolName(); 681 if (connectionPoolName != null) 682 { 683 buffer.append(" connectionPoolName=\""); 684 buffer.append(connectionPoolName); 685 buffer.append('"'); 686 } 687 688 buffer.append(' '); 689 } 690 691 buffer.append("disconnectedFrom=\""); 692 buffer.append(h); 693 buffer.append(':'); 694 buffer.append(p); 695 buffer.append("\" disconnectType=\""); 696 buffer.append(t.name()); 697 buffer.append('"'); 698 699 if (m != null) 700 { 701 buffer.append("\" disconnectMessage=\""); 702 buffer.append(m); 703 buffer.append('"'); 704 } 705 706 if (e != null) 707 { 708 buffer.append("\" disconnectCause=\""); 709 getStackTrace(e, buffer); 710 buffer.append('"'); 711 } 712 713 logger.log(l, buffer.toString(), c); 714 } 715 } 716 717 718 719 /** 720 * Writes debug information about the provided request, if appropriate. If 721 * it is to be logged, then it will be sent to the underlying logger using the 722 * {@code INFO} level. 723 * 724 * @param r The LDAP request for which debug information should be written. 725 */ 726 public static void debugLDAPRequest(final LDAPRequest r) 727 { 728 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 729 { 730 debugLDAPRequest(Level.INFO, r, -1, null); 731 } 732 } 733 734 735 736 /** 737 * Writes debug information about the provided request, if appropriate. 738 * 739 * @param l The log level that should be used for the debug information. 740 * @param r The LDAP request for which debug information should be written. 741 */ 742 public static void debugLDAPRequest(final Level l, final LDAPRequest r) 743 { 744 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 745 { 746 debugLDAPRequest(l, r, -1, null); 747 } 748 } 749 750 751 752 /** 753 * Writes debug information about the provided request, if appropriate. If 754 * it is to be logged, then it will be sent to the underlying logger using the 755 * {@code INFO} level. 756 * 757 * @param r The LDAP request for which debug information should be written. 758 * @param i The message ID for the request that will be sent. It may be 759 * negative if no message ID is available. 760 * @param c The connection on which the request will be sent. It may be 761 * {@code null} for historic reasons, but should be 762 * non-{@code null} in new uses. 763 */ 764 public static void debugLDAPRequest(final LDAPRequest r, final int i, 765 final LDAPConnection c) 766 { 767 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 768 { 769 debugLDAPRequest(Level.INFO, r, i, c); 770 } 771 } 772 773 774 775 /** 776 * Writes debug information about the provided request, if appropriate. 777 * 778 * @param l The log level that should be used for the debug information. 779 * @param r The LDAP request for which debug information should be written. 780 * @param i The message ID for the request that will be sent. It may be 781 * negative if no message ID is available. 782 * @param c The connection on which the request will be sent. It may be 783 * {@code null} for historic reasons, but should be 784 * non-{@code null} in new uses. 785 */ 786 public static void debugLDAPRequest(final Level l, final LDAPRequest r, 787 final int i, final LDAPConnection c) 788 { 789 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 790 { 791 final StringBuilder buffer = new StringBuilder(); 792 addCommonHeader(buffer, l); 793 794 if (c != null) 795 { 796 buffer.append("connectionID="); 797 buffer.append(c.getConnectionID()); 798 799 final String connectionName = c.getConnectionName(); 800 if (connectionName != null) 801 { 802 buffer.append(" connectionName=\""); 803 buffer.append(connectionName); 804 buffer.append('"'); 805 } 806 807 final String connectionPoolName = c.getConnectionPoolName(); 808 if (connectionPoolName != null) 809 { 810 buffer.append(" connectionPoolName=\""); 811 buffer.append(connectionPoolName); 812 buffer.append('"'); 813 } 814 815 buffer.append(" connectedTo=\""); 816 buffer.append(c.getConnectedAddress()); 817 buffer.append(':'); 818 buffer.append(c.getConnectedPort()); 819 buffer.append("\" "); 820 } 821 822 if (i >= 0) 823 { 824 buffer.append(" messageID="); 825 buffer.append(i); 826 buffer.append(' '); 827 } 828 829 buffer.append("sendingLDAPRequest=\""); 830 r.toString(buffer); 831 buffer.append('"'); 832 833 logger.log(l, buffer.toString()); 834 } 835 } 836 837 838 839 /** 840 * Writes debug information about the provided result, if appropriate. If 841 * it is to be logged, then it will be sent to the underlying logger using the 842 * {@code INFO} level. 843 * 844 * @param r The result for which debug information should be written. 845 */ 846 public static void debugLDAPResult(final LDAPResponse r) 847 { 848 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 849 { 850 debugLDAPResult(Level.INFO, r, null); 851 } 852 } 853 854 855 856 /** 857 * Writes debug information about the provided result, if appropriate. 858 * 859 * @param l The log level that should be used for the debug information. 860 * @param r The result for which debug information should be written. 861 */ 862 public static void debugLDAPResult(final Level l, final LDAPResponse r) 863 { 864 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 865 { 866 debugLDAPResult(l, r, null); 867 } 868 } 869 870 871 872 /** 873 * Writes debug information about the provided result, if appropriate. If 874 * it is to be logged, then it will be sent to the underlying logger using the 875 * {@code INFO} level. 876 * 877 * @param r The result for which debug information should be written. 878 * @param c The connection on which the response was received. It may be 879 * {@code null} for historic reasons, but should be 880 * non-{@code null} in new uses. 881 */ 882 public static void debugLDAPResult(final LDAPResponse r, 883 final LDAPConnection c) 884 { 885 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 886 { 887 debugLDAPResult(Level.INFO, r, c); 888 } 889 } 890 891 892 893 /** 894 * Writes debug information about the provided result, if appropriate. 895 * 896 * @param l The log level that should be used for the debug information. 897 * @param r The result for which debug information should be written. 898 * @param c The connection on which the response was received. It may be 899 * {@code null} for historic reasons, but should be 900 * non-{@code null} in new uses. 901 */ 902 public static void debugLDAPResult(final Level l, final LDAPResponse r, 903 final LDAPConnection c) 904 { 905 if (debugEnabled && debugTypes.contains(DebugType.LDAP)) 906 { 907 final StringBuilder buffer = new StringBuilder(); 908 addCommonHeader(buffer, l); 909 910 if (c != null) 911 { 912 buffer.append("connectionID="); 913 buffer.append(c.getConnectionID()); 914 915 final String connectionName = c.getConnectionName(); 916 if (connectionName != null) 917 { 918 buffer.append(" connectionName=\""); 919 buffer.append(connectionName); 920 buffer.append('"'); 921 } 922 923 final String connectionPoolName = c.getConnectionPoolName(); 924 if (connectionPoolName != null) 925 { 926 buffer.append(" connectionPoolName=\""); 927 buffer.append(connectionPoolName); 928 buffer.append('"'); 929 } 930 931 buffer.append(" connectedTo=\""); 932 buffer.append(c.getConnectedAddress()); 933 buffer.append(':'); 934 buffer.append(c.getConnectedPort()); 935 buffer.append("\" "); 936 } 937 938 buffer.append("readLDAPResult=\""); 939 r.toString(buffer); 940 buffer.append('"'); 941 942 logger.log(l, buffer.toString()); 943 } 944 } 945 946 947 948 /** 949 * Writes debug information about the provided ASN.1 element to be written, 950 * if appropriate. If it is to be logged, then it will be sent to the 951 * underlying logger using the {@code INFO} level. 952 * 953 * @param e The ASN.1 element for which debug information should be written. 954 */ 955 public static void debugASN1Write(final ASN1Element e) 956 { 957 if (debugEnabled && debugTypes.contains(DebugType.ASN1)) 958 { 959 debugASN1Write(Level.INFO, e); 960 } 961 } 962 963 964 965 /** 966 * Writes debug information about the provided ASN.1 element to be written, 967 * if appropriate. 968 * 969 * @param l The log level that should be used for the debug information. 970 * @param e The ASN.1 element for which debug information should be written. 971 */ 972 public static void debugASN1Write(final Level l, final ASN1Element e) 973 { 974 if (debugEnabled && debugTypes.contains(DebugType.ASN1)) 975 { 976 final StringBuilder buffer = new StringBuilder(); 977 addCommonHeader(buffer, l); 978 buffer.append("writingASN1Element=\""); 979 e.toString(buffer); 980 buffer.append('"'); 981 982 logger.log(l, buffer.toString()); 983 } 984 } 985 986 987 988 /** 989 * Writes debug information about the provided ASN.1 element to be written, 990 * if appropriate. If it is to be logged, then it will be sent to the 991 * underlying logger using the {@code INFO} level. 992 * 993 * @param b The ASN.1 buffer with the information to be written. 994 */ 995 public static void debugASN1Write(final ASN1Buffer b) 996 { 997 if (debugEnabled && debugTypes.contains(DebugType.ASN1)) 998 { 999 debugASN1Write(Level.INFO, b); 1000 } 1001 } 1002 1003 1004 1005 /** 1006 * Writes debug information about the provided ASN.1 element to be written, 1007 * if appropriate. 1008 * 1009 * @param l The log level that should be used for the debug information. 1010 * @param b The ASN1Buffer with the information to be written. 1011 */ 1012 public static void debugASN1Write(final Level l, final ASN1Buffer b) 1013 { 1014 if (debugEnabled && debugTypes.contains(DebugType.ASN1)) 1015 { 1016 final StringBuilder buffer = new StringBuilder(); 1017 addCommonHeader(buffer, l); 1018 buffer.append("writingASN1Element=\""); 1019 toHex(b.toByteArray(), buffer); 1020 buffer.append('"'); 1021 1022 logger.log(l, buffer.toString()); 1023 } 1024 } 1025 1026 1027 1028 /** 1029 * Writes debug information about the provided ASN.1 element that was read, if 1030 * appropriate. If it is to be logged, then it will be sent to the underlying 1031 * logger using the {@code INFO} level. 1032 * 1033 * @param e The ASN.1 element for which debug information should be written. 1034 */ 1035 public static void debugASN1Read(final ASN1Element e) 1036 { 1037 if (debugEnabled && debugTypes.contains(DebugType.ASN1)) 1038 { 1039 debugASN1Read(Level.INFO, e); 1040 } 1041 } 1042 1043 1044 1045 /** 1046 * Writes debug information about the provided ASN.1 element that was read, if 1047 * appropriate. 1048 * 1049 * @param l The log level that should be used for the debug information. 1050 * @param e The ASN.1 element for which debug information should be written. 1051 */ 1052 public static void debugASN1Read(final Level l, final ASN1Element e) 1053 { 1054 if (debugEnabled && debugTypes.contains(DebugType.ASN1)) 1055 { 1056 final StringBuilder buffer = new StringBuilder(); 1057 addCommonHeader(buffer, l); 1058 buffer.append("readASN1Element=\""); 1059 e.toString(buffer); 1060 buffer.append('"'); 1061 1062 logger.log(l, buffer.toString()); 1063 } 1064 } 1065 1066 1067 1068 /** 1069 * Writes debug information about the provided ASN.1 element that was read, if 1070 * appropriate. 1071 * 1072 * @param l The log level that should be used for the debug 1073 * information. 1074 * @param dataType A string representation of the data type for the data 1075 * that was read. 1076 * @param berType The BER type for the element that was read. 1077 * @param length The number of bytes in the value of the element that was 1078 * read. 1079 * @param value A representation of the value that was read. The debug 1080 * message will include the string representation of this 1081 * value, unless the value is a byte array in which it will 1082 * be a hex representation of the bytes that it contains. 1083 * It may be {@code null} for an ASN.1 null element. 1084 */ 1085 public static void debugASN1Read(final Level l, final String dataType, 1086 final int berType, final int length, 1087 final Object value) 1088 { 1089 if (debugEnabled && debugTypes.contains(DebugType.ASN1)) 1090 { 1091 final StringBuilder buffer = new StringBuilder(); 1092 addCommonHeader(buffer, l); 1093 buffer.append("readASN1Element=\"dataType='"); 1094 buffer.append(dataType); 1095 buffer.append("' berType='"); 1096 buffer.append(toHex((byte) (berType & 0xFF))); 1097 buffer.append('\''); 1098 buffer.append("' valueLength="); 1099 buffer.append(length); 1100 1101 if (value != null) 1102 { 1103 buffer.append(" value='"); 1104 if (value instanceof byte[]) 1105 { 1106 toHex((byte[]) value, buffer); 1107 } 1108 else 1109 { 1110 buffer.append(value); 1111 } 1112 buffer.append('\''); 1113 } 1114 buffer.append('"'); 1115 1116 logger.log(l, buffer.toString()); 1117 } 1118 } 1119 1120 1121 1122 /** 1123 * Writes debug information about the provided LDIF record to be written, if 1124 * if appropriate. If it is to be logged, then it will be sent to the 1125 * underlying logger using the {@code INFO} level. 1126 * 1127 * @param r The LDIF record for which debug information should be written. 1128 */ 1129 public static void debugLDIFWrite(final LDIFRecord r) 1130 { 1131 if (debugEnabled && debugTypes.contains(DebugType.LDIF)) 1132 { 1133 debugLDIFWrite(Level.INFO, r); 1134 } 1135 } 1136 1137 1138 1139 /** 1140 * Writes debug information about the provided LDIF record to be written, if 1141 * appropriate. 1142 * 1143 * @param l The log level that should be used for the debug information. 1144 * @param r The LDIF record for which debug information should be written. 1145 */ 1146 public static void debugLDIFWrite(final Level l, final LDIFRecord r) 1147 { 1148 if (debugEnabled && debugTypes.contains(DebugType.LDIF)) 1149 { 1150 final StringBuilder buffer = new StringBuilder(); 1151 addCommonHeader(buffer, l); 1152 buffer.append("writingLDIFRecord=\""); 1153 r.toString(buffer); 1154 buffer.append('"'); 1155 1156 logger.log(l, buffer.toString()); 1157 } 1158 } 1159 1160 1161 1162 /** 1163 * Writes debug information about the provided record read from LDIF, if 1164 * appropriate. If it is to be logged, then it will be sent to the underlying 1165 * logger using the {@code INFO} level. 1166 * 1167 * @param r The LDIF record for which debug information should be written. 1168 */ 1169 public static void debugLDIFRead(final LDIFRecord r) 1170 { 1171 if (debugEnabled && debugTypes.contains(DebugType.LDIF)) 1172 { 1173 debugLDIFRead(Level.INFO, r); 1174 } 1175 } 1176 1177 1178 1179 /** 1180 * Writes debug information about the provided record read from LDIF, if 1181 * appropriate. 1182 * 1183 * @param l The log level that should be used for the debug information. 1184 * @param r The LDIF record for which debug information should be written. 1185 */ 1186 public static void debugLDIFRead(final Level l, final LDIFRecord r) 1187 { 1188 if (debugEnabled && debugTypes.contains(DebugType.LDIF)) 1189 { 1190 final StringBuilder buffer = new StringBuilder(); 1191 addCommonHeader(buffer, l); 1192 buffer.append("readLDIFRecord=\""); 1193 r.toString(buffer); 1194 buffer.append('"'); 1195 1196 logger.log(l, buffer.toString()); 1197 } 1198 } 1199 1200 1201 1202 /** 1203 * Writes debug information about monitor entry parsing. If it is to be 1204 * logged, then it will be sent to the underlying logger using the 1205 * {@code FINE} level. 1206 * 1207 * @param e The entry containing the monitor information being parsed. 1208 * @param m The message to be written to the debug logger. 1209 */ 1210 public static void debugMonitor(final Entry e, final String m) 1211 { 1212 if (debugEnabled && debugTypes.contains(DebugType.MONITOR)) 1213 { 1214 debugMonitor(Level.FINE, e, m); 1215 } 1216 } 1217 1218 1219 1220 /** 1221 * Writes debug information about monitor entry parsing, if appropriate. 1222 * 1223 * @param l The log level that should be used for the debug information. 1224 * @param e The entry containing the monitor information being parsed. 1225 * @param m The message to be written to the debug logger. 1226 */ 1227 public static void debugMonitor(final Level l, final Entry e, final String m) 1228 { 1229 if (debugEnabled && debugTypes.contains(DebugType.MONITOR)) 1230 { 1231 final StringBuilder buffer = new StringBuilder(); 1232 addCommonHeader(buffer, l); 1233 buffer.append("monitorEntryDN=\""); 1234 buffer.append(e.getDN()); 1235 buffer.append("\" message=\""); 1236 buffer.append(m); 1237 buffer.append('"'); 1238 1239 logger.log(l, buffer.toString()); 1240 } 1241 } 1242 1243 1244 1245 /** 1246 * Writes debug information about a coding error detected in the use of the 1247 * LDAP SDK. If it is to be logged, then it will be sent to the underlying 1248 * logger using the {@code SEVERE} level. 1249 * 1250 * @param t The {@code Throwable} object that was created and will be thrown 1251 * as a result of the coding error. 1252 */ 1253 public static void debugCodingError(final Throwable t) 1254 { 1255 if (debugEnabled && debugTypes.contains(DebugType.CODING_ERROR)) 1256 { 1257 final StringBuilder buffer = new StringBuilder(); 1258 addCommonHeader(buffer, Level.SEVERE); 1259 buffer.append("codingError=\""); 1260 getStackTrace(t, buffer); 1261 buffer.append('"'); 1262 1263 logger.log(Level.SEVERE, buffer.toString()); 1264 } 1265 } 1266 1267 1268 1269 /** 1270 * Writes a generic debug message, if appropriate. 1271 * 1272 * @param l The log level that should be used for the debug information. 1273 * @param t The debug type to use to determine whether to write the message. 1274 * @param m The message to be written. 1275 */ 1276 public static void debug(final Level l, final DebugType t, final String m) 1277 { 1278 if (debugEnabled && debugTypes.contains(t)) 1279 { 1280 final StringBuilder buffer = new StringBuilder(); 1281 addCommonHeader(buffer, l); 1282 buffer.append("message=\""); 1283 buffer.append(m); 1284 buffer.append('"'); 1285 1286 logger.log(l, buffer.toString()); 1287 } 1288 } 1289 1290 1291 1292 /** 1293 * Writes a generic debug message, if appropriate. 1294 * 1295 * @param l The log level that should be used for the debug information. 1296 * @param t The debug type to use to determine whether to write the message. 1297 * @param m The message to be written. 1298 * @param e An exception to include with the log message. 1299 */ 1300 public static void debug(final Level l, final DebugType t, final String m, 1301 final Throwable e) 1302 { 1303 if (debugEnabled && debugTypes.contains(t)) 1304 { 1305 final StringBuilder buffer = new StringBuilder(); 1306 addCommonHeader(buffer, l); 1307 buffer.append("message=\""); 1308 buffer.append(m); 1309 buffer.append('"'); 1310 buffer.append(" exception=\""); 1311 getStackTrace(e, buffer); 1312 buffer.append('"'); 1313 1314 logger.log(l, buffer.toString(), e); 1315 } 1316 } 1317 1318 1319 1320 /** 1321 * Writes common header information to the provided buffer. It will include 1322 * the thread ID, name, and caller stack trace (optional), and it will be 1323 * followed by a trailing space. 1324 * 1325 * @param buffer The buffer to which the information should be appended. 1326 * @param level The log level for the message that will be written. 1327 */ 1328 private static void addCommonHeader(final StringBuilder buffer, 1329 final Level level) 1330 { 1331 buffer.append("level=\""); 1332 buffer.append(level.getName()); 1333 buffer.append("\" threadID="); 1334 buffer.append(Thread.currentThread().getId()); 1335 buffer.append(" threadName=\""); 1336 buffer.append(Thread.currentThread().getName()); 1337 1338 if (includeStackTrace) 1339 { 1340 buffer.append("\" calledFrom=\""); 1341 1342 boolean appended = false; 1343 boolean foundDebug = false; 1344 for (final StackTraceElement e : Thread.currentThread().getStackTrace()) 1345 { 1346 final String className = e.getClassName(); 1347 if (className.equals(Debug.class.getName())) 1348 { 1349 foundDebug = true; 1350 } 1351 else if (foundDebug) 1352 { 1353 if (appended) 1354 { 1355 buffer.append(" / "); 1356 } 1357 appended = true; 1358 1359 buffer.append(e.getMethodName()); 1360 buffer.append('('); 1361 buffer.append(e.getFileName()); 1362 1363 final int lineNumber = e.getLineNumber(); 1364 if (lineNumber > 0) 1365 { 1366 buffer.append(':'); 1367 buffer.append(lineNumber); 1368 } 1369 else if (e.isNativeMethod()) 1370 { 1371 buffer.append(":native"); 1372 } 1373 1374 buffer.append(')'); 1375 } 1376 } 1377 } 1378 1379 buffer.append("\" revision="); 1380 buffer.append(Version.REVISION_NUMBER); 1381 buffer.append(' '); 1382 } 1383}