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