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