001/*
002 * Copyright 2007-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2018 Ping Identity Corporation
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.ldap.sdk;
022
023
024
025import com.unboundid.util.Debug;
026import com.unboundid.util.LDAPSDKException;
027import com.unboundid.util.NotExtensible;
028import com.unboundid.util.NotMutable;
029import com.unboundid.util.StaticUtils;
030import com.unboundid.util.ThreadSafety;
031import com.unboundid.util.ThreadSafetyLevel;
032
033
034
035/**
036 * This class defines an exception that can be thrown if a problem occurs while
037 * performing LDAP-related processing.  An LDAP exception can include all of
038 * the elements of an {@link LDAPResult}, so that all of the response elements
039 * will be available.
040 */
041@NotExtensible()
042@NotMutable()
043@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
044public class LDAPException
045       extends LDAPSDKException
046{
047  /**
048   * The serial version UID for this serializable class.
049   */
050  private static final long serialVersionUID = -4257171063946350327L;
051
052
053
054  /**
055   * An empty array that will be used when no controls were provided.
056   */
057  protected static final Control[] NO_CONTROLS = StaticUtils.NO_CONTROLS;
058
059
060
061  /**
062   * An empty array that will be used when no referrals were provided.
063   */
064  protected static final String[] NO_REFERRALS = StaticUtils.NO_STRINGS;
065
066
067
068  // The set of response controls for this LDAP exception.
069  private final Control[] responseControls;
070
071  // The result code for this LDAP exception.
072  private final ResultCode resultCode;
073
074  // The set of referral URLs for this LDAP exception.
075  private final String[] referralURLs;
076
077  // The diagnostic message returned by the directory server.
078  private final String diagnosticMessage;
079
080  // The matched DN for this LDAP exception.
081  private final String matchedDN;
082
083
084
085  /**
086   * Creates a new LDAP exception with the provided result code.  A default
087   * message (based on the result code) will be used.
088   *
089   * @param  resultCode  The result code for this LDAP exception.
090   */
091  public LDAPException(final ResultCode resultCode)
092  {
093    super(resultCode.getName());
094
095    this.resultCode = resultCode;
096
097    matchedDN         = null;
098    diagnosticMessage = null;
099    referralURLs      = NO_REFERRALS;
100    responseControls  = NO_CONTROLS;
101  }
102
103
104
105  /**
106   * Creates a new LDAP exception with the provided result code.  A default
107   * message (based on the result code) will be used.
108   *
109   * @param  resultCode  The result code for this LDAP exception.
110   * @param  cause       The underlying exception that triggered this exception.
111   */
112  public LDAPException(final ResultCode resultCode, final Throwable cause)
113  {
114    super(resultCode.getName(), cause);
115
116    this.resultCode = resultCode;
117
118    matchedDN         = null;
119    diagnosticMessage = null;
120    referralURLs      = NO_REFERRALS;
121    responseControls  = NO_CONTROLS;
122  }
123
124
125
126  /**
127   * Creates a new LDAP exception with the provided result code and message.
128   *
129   * @param  resultCode    The result code for this LDAP exception.
130   * @param  errorMessage  The error message for this LDAP exception.
131   */
132  public LDAPException(final ResultCode resultCode, final String errorMessage)
133  {
134    super(errorMessage);
135
136    this.resultCode = resultCode;
137
138    matchedDN         = null;
139    diagnosticMessage = null;
140    referralURLs      = NO_REFERRALS;
141    responseControls  = NO_CONTROLS;
142  }
143
144
145
146  /**
147   * Creates a new LDAP exception with the provided result code and message.
148   *
149   * @param  resultCode    The result code for this LDAP exception.
150   * @param  errorMessage  The error message for this LDAP exception.
151   * @param  cause         The underlying exception that triggered this
152   *                       exception.
153   */
154  public LDAPException(final ResultCode resultCode, final String errorMessage,
155                       final Throwable cause)
156  {
157    super(errorMessage, cause);
158
159    this.resultCode = resultCode;
160
161    matchedDN         = null;
162    diagnosticMessage = null;
163    referralURLs      = NO_REFERRALS;
164    responseControls  = NO_CONTROLS;
165  }
166
167
168
169  /**
170   * Creates a new LDAP exception with the provided information.
171   *
172   * @param  resultCode    The result code for this LDAP exception.
173   * @param  errorMessage  The error message for this LDAP exception.
174   * @param  matchedDN     The matched DN for this LDAP exception.
175   * @param  referralURLs  The set of referral URLs for this LDAP exception.
176   */
177  public LDAPException(final ResultCode resultCode, final String errorMessage,
178                       final String matchedDN, final String[] referralURLs)
179  {
180    super(errorMessage);
181
182    this.resultCode = resultCode;
183    this.matchedDN  = matchedDN;
184
185    if (referralURLs == null)
186    {
187      this.referralURLs = NO_REFERRALS;
188    }
189    else
190    {
191      this.referralURLs = referralURLs;
192    }
193
194    diagnosticMessage = null;
195    responseControls  = NO_CONTROLS;
196  }
197
198
199
200  /**
201   * Creates a new LDAP exception with the provided information.
202   *
203   * @param  resultCode    The result code for this LDAP exception.
204   * @param  errorMessage  The error message for this LDAP exception.
205   * @param  matchedDN     The matched DN for this LDAP exception.
206   * @param  referralURLs  The set of referral URLs for this LDAP exception.
207   * @param  cause         The underlying exception that triggered this
208   *                       exception.
209   */
210  public LDAPException(final ResultCode resultCode, final String errorMessage,
211                       final String matchedDN, final String[] referralURLs,
212                       final Throwable cause)
213  {
214    super(errorMessage, cause);
215
216    this.resultCode = resultCode;
217    this.matchedDN  = matchedDN;
218
219    if (referralURLs == null)
220    {
221      this.referralURLs = NO_REFERRALS;
222    }
223    else
224    {
225      this.referralURLs = referralURLs;
226    }
227
228    diagnosticMessage = null;
229    responseControls  = NO_CONTROLS;
230  }
231
232
233
234  /**
235   * Creates a new LDAP exception with the provided information.
236   *
237   * @param  resultCode    The result code for this LDAP exception.
238   * @param  errorMessage  The error message for this LDAP exception.
239   * @param  matchedDN     The matched DN for this LDAP exception.
240   * @param  referralURLs  The set of referral URLs for this LDAP exception.
241   * @param  controls      The set of response controls for this LDAP exception.
242   */
243  public LDAPException(final ResultCode resultCode, final String errorMessage,
244                       final String matchedDN, final String[] referralURLs,
245                       final Control[] controls)
246  {
247    super(errorMessage);
248
249    this.resultCode = resultCode;
250    this.matchedDN  = matchedDN;
251
252    diagnosticMessage = null;
253
254    if (referralURLs == null)
255    {
256      this.referralURLs = NO_REFERRALS;
257    }
258    else
259    {
260      this.referralURLs = referralURLs;
261    }
262
263    if (controls == null)
264    {
265      responseControls = NO_CONTROLS;
266    }
267    else
268    {
269      responseControls = controls;
270    }
271  }
272
273
274
275  /**
276   * Creates a new LDAP exception with the provided information.
277   *
278   * @param  resultCode    The result code for this LDAP exception.
279   * @param  errorMessage  The error message for this LDAP exception.
280   * @param  matchedDN     The matched DN for this LDAP exception.
281   * @param  referralURLs  The set of referral URLs for this LDAP exception.
282   * @param  controls      The set of response controls for this LDAP exception.
283   * @param  cause         The underlying exception that triggered this
284   *                       exception.
285   */
286  public LDAPException(final ResultCode resultCode, final String errorMessage,
287                       final String matchedDN, final String[] referralURLs,
288                       final Control[] controls, final Throwable cause)
289  {
290    super(errorMessage, cause);
291
292    this.resultCode = resultCode;
293    this.matchedDN  = matchedDN;
294
295    diagnosticMessage = null;
296
297    if (referralURLs == null)
298    {
299      this.referralURLs = NO_REFERRALS;
300    }
301    else
302    {
303      this.referralURLs = referralURLs;
304    }
305
306    if (controls == null)
307    {
308      responseControls = NO_CONTROLS;
309    }
310    else
311    {
312      responseControls = controls;
313    }
314  }
315
316
317
318  /**
319   * Creates a new LDAP exception using the information contained in the
320   * provided LDAP result object.
321   *
322   * @param  ldapResult  The LDAP result object containing the information to
323   *                     use for this LDAP exception.
324   */
325  public LDAPException(final LDAPResult ldapResult)
326  {
327    super((ldapResult.getDiagnosticMessage() == null)
328          ? ldapResult.getResultCode().getName()
329          : ldapResult.getDiagnosticMessage());
330
331    resultCode        = ldapResult.getResultCode();
332    matchedDN         = ldapResult.getMatchedDN();
333    diagnosticMessage = ldapResult.getDiagnosticMessage();
334    referralURLs      = ldapResult.getReferralURLs();
335    responseControls  = ldapResult.getResponseControls();
336  }
337
338
339
340  /**
341   * Creates a new LDAP exception using the information contained in the
342   * provided LDAP result object.
343   *
344   * @param  ldapResult  The LDAP result object containing the information to
345   *                     use for this LDAP exception.
346   * @param  cause       The underlying exception that triggered this exception.
347   */
348  public LDAPException(final LDAPResult ldapResult, final Throwable cause)
349  {
350    super(((ldapResult.getDiagnosticMessage() == null)
351           ? ldapResult.getResultCode().getName()
352           : ldapResult.getDiagnosticMessage()),
353          cause);
354
355    resultCode        = ldapResult.getResultCode();
356    matchedDN         = ldapResult.getMatchedDN();
357    diagnosticMessage = ldapResult.getDiagnosticMessage();
358    referralURLs      = ldapResult.getReferralURLs();
359    responseControls  = ldapResult.getResponseControls();
360  }
361
362
363
364  /**
365   * Creates a new LDAP exception using the information contained in the
366   * provided LDAP exception.
367   *
368   * @param  e  The LDAP exception to use to create this exception.
369   */
370  public LDAPException(final LDAPException e)
371  {
372    super(e.getMessage(), e.getCause());
373
374    resultCode        = e.getResultCode();
375    matchedDN         = e.getMatchedDN();
376    diagnosticMessage = e.getDiagnosticMessage();
377    referralURLs      = e.getReferralURLs();
378    responseControls  = e.getResponseControls();
379  }
380
381
382
383  /**
384   * Retrieves the result code for this LDAP exception.
385   *
386   * @return  The result code for this LDAP exception.
387   */
388  public final ResultCode getResultCode()
389  {
390    return resultCode;
391  }
392
393
394
395  /**
396   * Retrieves the matched DN for this LDAP exception.
397   *
398   * @return  The matched DN for this LDAP exception, or {@code null} if there
399   *          is none.
400   */
401  public final String getMatchedDN()
402  {
403    return matchedDN;
404  }
405
406
407
408  /**
409   * Retrieves the diagnostic message returned by the directory server.
410   *
411   * @return  The diagnostic message returned by the directory server, or
412   *          {@code null} if there is none.
413   */
414  public final String getDiagnosticMessage()
415  {
416    return diagnosticMessage;
417  }
418
419
420
421  /**
422   * Retrieves the set of referral URLs for this LDAP exception.
423   *
424   * @return  The set of referral URLs for this LDAP exception, or an empty
425   *          array if there are none.
426   */
427  public final String[] getReferralURLs()
428  {
429    return referralURLs;
430  }
431
432
433
434  /**
435   * Indicates whether this result contains at least one control.
436   *
437   * @return  {@code true} if this result contains at least one control, or
438   *          {@code false} if not.
439   */
440  public final boolean hasResponseControl()
441  {
442    return (responseControls.length > 0);
443  }
444
445
446
447  /**
448   * Indicates whether this result contains at least one control with the
449   * specified OID.
450   *
451   * @param  oid  The object identifier for which to make the determination.  It
452   *              must not be {@code null}.
453   *
454   * @return  {@code true} if this result contains at least one control with
455   *          the specified OID, or {@code false} if not.
456   */
457  public final boolean hasResponseControl(final String oid)
458  {
459    for (final Control c : responseControls)
460    {
461      if (c.getOID().equals(oid))
462      {
463        return true;
464      }
465    }
466
467    return false;
468  }
469
470
471
472  /**
473   * Retrieves the set of response controls for this LDAP exception.
474   * Individual response controls of a specific type may be retrieved and
475   * decoded using the {@code get} method in the response control class, using
476   * the {@link #toLDAPResult()} method to convert this exception to an
477   * {@link LDAPResult}.
478   *
479   * @return  The set of response controls for this LDAP exception, or an empty
480   *          array if there are none.
481   */
482  public final Control[] getResponseControls()
483  {
484    return responseControls;
485  }
486
487
488
489  /**
490   * Retrieves the response control with the specified OID.
491   *
492   * @param  oid  The OID of the control to retrieve.
493   *
494   * @return  The response control with the specified OID, or {@code null} if
495   *          there is no such control.
496   */
497  public final Control getResponseControl(final String oid)
498  {
499    for (final Control c : responseControls)
500    {
501      if (c.getOID().equals(oid))
502      {
503        return c;
504      }
505    }
506
507    return null;
508  }
509
510
511
512  /**
513   * Creates a new {@code LDAPResult} object from this exception.
514   *
515   * @return  The {@code LDAPResult} object created from this exception.
516   */
517  public LDAPResult toLDAPResult()
518  {
519    if ((diagnosticMessage == null) && (getMessage() != null))
520    {
521      return new LDAPResult(-1, resultCode, getMessage(), matchedDN,
522           referralURLs, responseControls);
523    }
524    else
525    {
526      return new LDAPResult(-1, resultCode, diagnosticMessage, matchedDN,
527           referralURLs, responseControls);
528    }
529  }
530
531
532
533  /**
534   * Retrieves a string representation of this LDAP result, consisting of
535   * the result code, diagnostic message (if present), matched DN (if present),
536   * and referral URLs (if present).
537   *
538   * @return  A string representation of this LDAP result.
539   */
540  public String getResultString()
541  {
542    final StringBuilder buffer = new StringBuilder();
543    buffer.append("result code='");
544    buffer.append(resultCode);
545    buffer.append('\'');
546
547    if ((diagnosticMessage != null) && (diagnosticMessage.length() > 0))
548    {
549      buffer.append(" diagnostic message='");
550      buffer.append(diagnosticMessage);
551      buffer.append('\'');
552    }
553
554    if ((matchedDN != null) && (matchedDN.length() > 0))
555    {
556      buffer.append("  matched DN='");
557      buffer.append(matchedDN);
558      buffer.append('\'');
559    }
560
561    if ((referralURLs != null) && (referralURLs.length > 0))
562    {
563      buffer.append("  referral URLs={");
564
565      for (int i=0; i < referralURLs.length; i++)
566      {
567        if (i > 0)
568        {
569          buffer.append(", ");
570        }
571
572        buffer.append('\'');
573        buffer.append(referralURLs[i]);
574        buffer.append('\'');
575      }
576
577      buffer.append('}');
578    }
579
580    return buffer.toString();
581  }
582
583
584
585  /**
586   * {@inheritDoc}
587   */
588  @Override()
589  public void toString(final StringBuilder buffer)
590  {
591    final boolean includeCause =
592         Boolean.getBoolean(Debug.PROPERTY_INCLUDE_CAUSE_IN_EXCEPTION_MESSAGES);
593    final boolean includeStackTrace = Boolean.getBoolean(
594         Debug.PROPERTY_INCLUDE_STACK_TRACE_IN_EXCEPTION_MESSAGES);
595
596    toString(buffer, includeCause, includeStackTrace);
597  }
598
599
600
601  /**
602   * Appends a string representation of this {@code LDAPException} to the
603   * provided buffer.
604   *
605   * @param  buffer             The buffer to which the information should be
606   *                            appended.  This must not be {@code null}.
607   * @param  includeCause       Indicates whether to include information about
608   *                            the cause (if any) in the exception message.
609   * @param  includeStackTrace  Indicates whether to include a condensed
610   *                            representation of the stack trace in the
611   *                            exception message.  If a stack trace is
612   *                            included, then the cause (if any) will
613   *                            automatically be included, regardless of the
614   *                            value of the {@code includeCause} argument.
615   */
616  public void toString(final StringBuilder buffer, final boolean includeCause,
617                       final boolean includeStackTrace)
618  {
619    buffer.append("LDAPException(resultCode=");
620    buffer.append(resultCode);
621
622    final String errorMessage = getMessage();
623    if ((errorMessage != null) && (! errorMessage.equals(diagnosticMessage)))
624    {
625      buffer.append(", errorMessage='");
626      buffer.append(errorMessage);
627      buffer.append('\'');
628    }
629
630    if (diagnosticMessage != null)
631    {
632      buffer.append(", diagnosticMessage='");
633      buffer.append(diagnosticMessage);
634      buffer.append('\'');
635    }
636
637    if (matchedDN != null)
638    {
639      buffer.append(", matchedDN='");
640      buffer.append(matchedDN);
641      buffer.append('\'');
642    }
643
644    if (referralURLs.length > 0)
645    {
646      buffer.append(", referralURLs={");
647
648      for (int i=0; i < referralURLs.length; i++)
649      {
650        if (i > 0)
651        {
652          buffer.append(", ");
653        }
654
655        buffer.append('\'');
656        buffer.append(referralURLs[i]);
657        buffer.append('\'');
658      }
659
660      buffer.append('}');
661    }
662
663    if (responseControls.length > 0)
664    {
665      buffer.append(", responseControls={");
666
667      for (int i=0; i < responseControls.length; i++)
668      {
669        if (i > 0)
670        {
671          buffer.append(", ");
672        }
673
674        buffer.append(responseControls[i]);
675      }
676
677      buffer.append('}');
678    }
679
680    if (includeStackTrace)
681    {
682      buffer.append(", trace='");
683      StaticUtils.getStackTrace(getStackTrace(), buffer);
684      buffer.append('\'');
685    }
686
687    if (includeCause || includeStackTrace)
688    {
689      final Throwable cause = getCause();
690      if (cause != null)
691      {
692        buffer.append(", cause=");
693        buffer.append(StaticUtils.getExceptionMessage(cause, true,
694             includeStackTrace));
695      }
696    }
697
698    final String ldapSDKVersionString = ", ldapSDKVersion=" +
699         Version.NUMERIC_VERSION_STRING + ", revision=" + Version.REVISION_ID;
700    if (buffer.indexOf(ldapSDKVersionString) < 0)
701    {
702      buffer.append(ldapSDKVersionString);
703    }
704
705    buffer.append(')');
706  }
707
708
709
710  /**
711   * {@inheritDoc}
712   */
713  @Override()
714  public final String getExceptionMessage()
715  {
716    return toString();
717  }
718
719
720
721  /**
722   * {@inheritDoc}
723   */
724  @Override()
725  public final String getExceptionMessage(final boolean includeCause,
726                                          final boolean includeStackTrace)
727  {
728    final StringBuilder buffer = new StringBuilder();
729    toString(buffer, includeCause, includeStackTrace);
730    return buffer.toString();
731  }
732}