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