001/* 002 * Copyright 2008-2014 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2014 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 LDIF record to be written, if 1070 * if appropriate. If it is to be logged, then it will be sent to the 1071 * underlying logger using the {@code INFO} level. 1072 * 1073 * @param r The LDIF record for which debug information should be written. 1074 */ 1075 public static void debugLDIFWrite(final LDIFRecord r) 1076 { 1077 if (debugEnabled && debugTypes.contains(DebugType.LDIF)) 1078 { 1079 debugLDIFWrite(Level.INFO, r); 1080 } 1081 } 1082 1083 1084 1085 /** 1086 * Writes debug information about the provided LDIF record to be written, if 1087 * appropriate. 1088 * 1089 * @param l The log level that should be used for the debug information. 1090 * @param r The LDIF record for which debug information should be written. 1091 */ 1092 public static void debugLDIFWrite(final Level l, final LDIFRecord r) 1093 { 1094 if (debugEnabled && debugTypes.contains(DebugType.LDIF)) 1095 { 1096 final StringBuilder buffer = new StringBuilder(); 1097 addCommonHeader(buffer, l); 1098 buffer.append("writingLDIFRecord=\""); 1099 r.toString(buffer); 1100 buffer.append('"'); 1101 1102 logger.log(l, buffer.toString()); 1103 } 1104 } 1105 1106 1107 1108 /** 1109 * Writes debug information about the provided record read from LDIF, if 1110 * appropriate. If it is to be logged, then it will be sent to the underlying 1111 * logger using the {@code INFO} level. 1112 * 1113 * @param r The LDIF record for which debug information should be written. 1114 */ 1115 public static void debugLDIFRead(final LDIFRecord r) 1116 { 1117 if (debugEnabled && debugTypes.contains(DebugType.LDIF)) 1118 { 1119 debugLDIFRead(Level.INFO, r); 1120 } 1121 } 1122 1123 1124 1125 /** 1126 * Writes debug information about the provided record read from LDIF, if 1127 * appropriate. 1128 * 1129 * @param l The log level that should be used for the debug information. 1130 * @param r The LDIF record for which debug information should be written. 1131 */ 1132 public static void debugLDIFRead(final Level l, final LDIFRecord r) 1133 { 1134 if (debugEnabled && debugTypes.contains(DebugType.LDIF)) 1135 { 1136 final StringBuilder buffer = new StringBuilder(); 1137 addCommonHeader(buffer, l); 1138 buffer.append("readLDIFRecord=\""); 1139 r.toString(buffer); 1140 buffer.append('"'); 1141 1142 logger.log(l, buffer.toString()); 1143 } 1144 } 1145 1146 1147 1148 /** 1149 * Writes debug information about monitor entry parsing. If it is to be 1150 * logged, then it will be sent to the underlying logger using the 1151 * {@code FINE} level. 1152 * 1153 * @param e The entry containing the monitor information being parsed. 1154 * @param m The message to be written to the debug logger. 1155 */ 1156 public static void debugMonitor(final Entry e, final String m) 1157 { 1158 if (debugEnabled && debugTypes.contains(DebugType.MONITOR)) 1159 { 1160 debugMonitor(Level.FINE, e, m); 1161 } 1162 } 1163 1164 1165 1166 /** 1167 * Writes debug information about monitor entry parsing, if appropriate. 1168 * 1169 * @param l The log level that should be used for the debug information. 1170 * @param e The entry containing the monitor information being parsed. 1171 * @param m The message to be written to the debug logger. 1172 */ 1173 public static void debugMonitor(final Level l, final Entry e, final String m) 1174 { 1175 if (debugEnabled && debugTypes.contains(DebugType.MONITOR)) 1176 { 1177 final StringBuilder buffer = new StringBuilder(); 1178 addCommonHeader(buffer, l); 1179 buffer.append("monitorEntryDN=\""); 1180 buffer.append(e.getDN()); 1181 buffer.append("\" message=\""); 1182 buffer.append(m); 1183 buffer.append('"'); 1184 1185 logger.log(l, buffer.toString()); 1186 } 1187 } 1188 1189 1190 1191 /** 1192 * Writes debug information about a coding error detected in the use of the 1193 * LDAP SDK. If it is to be logged, then it will be sent to the underlying 1194 * logger using the {@code SEVERE} level. 1195 * 1196 * @param t The {@code Throwable} object that was created and will be thrown 1197 * as a result of the coding error. 1198 */ 1199 public static void debugCodingError(final Throwable t) 1200 { 1201 if (debugEnabled && debugTypes.contains(DebugType.CODING_ERROR)) 1202 { 1203 final StringBuilder buffer = new StringBuilder(); 1204 addCommonHeader(buffer, Level.SEVERE); 1205 buffer.append("codingError=\""); 1206 getStackTrace(t, buffer); 1207 buffer.append('"'); 1208 1209 logger.log(Level.SEVERE, buffer.toString()); 1210 } 1211 } 1212 1213 1214 1215 /** 1216 * Writes a generic debug message, if appropriate. 1217 * 1218 * @param l The log level that should be used for the debug information. 1219 * @param t The debug type to use to determine whether to write the message. 1220 * @param m The message to be written. 1221 */ 1222 public static void debug(final Level l, final DebugType t, final String m) 1223 { 1224 if (debugEnabled && debugTypes.contains(t)) 1225 { 1226 final StringBuilder buffer = new StringBuilder(); 1227 addCommonHeader(buffer, l); 1228 buffer.append("message=\""); 1229 buffer.append(m); 1230 buffer.append('"'); 1231 1232 logger.log(l, buffer.toString()); 1233 } 1234 } 1235 1236 1237 1238 /** 1239 * Writes a generic debug message, if appropriate. 1240 * 1241 * @param l The log level that should be used for the debug information. 1242 * @param t The debug type to use to determine whether to write the message. 1243 * @param m The message to be written. 1244 * @param e An exception to include with the log message. 1245 */ 1246 public static void debug(final Level l, final DebugType t, final String m, 1247 final Throwable e) 1248 { 1249 if (debugEnabled && debugTypes.contains(t)) 1250 { 1251 final StringBuilder buffer = new StringBuilder(); 1252 addCommonHeader(buffer, l); 1253 buffer.append("message=\""); 1254 buffer.append(m); 1255 buffer.append('"'); 1256 buffer.append(" exception=\""); 1257 getStackTrace(e, buffer); 1258 buffer.append('"'); 1259 1260 logger.log(l, buffer.toString(), e); 1261 } 1262 } 1263 1264 1265 1266 /** 1267 * Writes common header information to the provided buffer. It will include 1268 * the thread ID, name, and caller stack trace (optional), and it will be 1269 * followed by a trailing space. 1270 * 1271 * @param buffer The buffer to which the information should be appended. 1272 * @param level The log level for the message that will be written. 1273 */ 1274 private static void addCommonHeader(final StringBuilder buffer, 1275 final Level level) 1276 { 1277 buffer.append("level=\""); 1278 buffer.append(level.getName()); 1279 buffer.append("\" threadID="); 1280 buffer.append(Thread.currentThread().getId()); 1281 buffer.append(" threadName=\""); 1282 buffer.append(Thread.currentThread().getName()); 1283 1284 if (includeStackTrace) 1285 { 1286 buffer.append("\" calledFrom=\""); 1287 1288 boolean appended = false; 1289 boolean foundDebug = false; 1290 for (final StackTraceElement e : Thread.currentThread().getStackTrace()) 1291 { 1292 final String className = e.getClassName(); 1293 if (className.equals(Debug.class.getName())) 1294 { 1295 foundDebug = true; 1296 } 1297 else if (foundDebug) 1298 { 1299 if (appended) 1300 { 1301 buffer.append(" / "); 1302 } 1303 appended = true; 1304 1305 buffer.append(e.getMethodName()); 1306 buffer.append('('); 1307 buffer.append(e.getFileName()); 1308 1309 final int lineNumber = e.getLineNumber(); 1310 if (lineNumber > 0) 1311 { 1312 buffer.append(':'); 1313 buffer.append(lineNumber); 1314 } 1315 else if (e.isNativeMethod()) 1316 { 1317 buffer.append(":native"); 1318 } 1319 1320 buffer.append(')'); 1321 } 1322 } 1323 } 1324 1325 buffer.append("\" revision="); 1326 buffer.append(Version.REVISION_NUMBER); 1327 buffer.append(' '); 1328 } 1329}