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.isEmpty())) 548 { 549 buffer.append(" diagnostic message='"); 550 buffer.append(diagnosticMessage); 551 buffer.append('\''); 552 } 553 554 if ((matchedDN != null) && (! matchedDN.isEmpty())) 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}