001 /*
002 * Copyright 2008-2013 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2013 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 {@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 file named "/tmp/test.log":
068 * <PRE>
069 * Debug.setEnabled(true);
070 * Logger logger = Debug.getLogger();
071 *
072 * FileHandler fileHandler = new FileHandler("/tmp/test.log");
073 * fileHandler.setLevel(Level.WARNING);
074 * logger.addHandler(fileHandler);
075 * </PRE>
076 */
077 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
078 public 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 }