001/* 002 * Copyright 2010-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2010-2017 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 */ 021package com.unboundid.ldap.listener; 022 023 024 025import java.net.Socket; 026import java.util.Arrays; 027import java.util.List; 028import java.util.logging.Handler; 029import java.util.logging.Level; 030import java.util.logging.LogRecord; 031 032import com.unboundid.asn1.ASN1OctetString; 033import com.unboundid.ldap.protocol.AbandonRequestProtocolOp; 034import com.unboundid.ldap.protocol.AddRequestProtocolOp; 035import com.unboundid.ldap.protocol.AddResponseProtocolOp; 036import com.unboundid.ldap.protocol.BindRequestProtocolOp; 037import com.unboundid.ldap.protocol.BindResponseProtocolOp; 038import com.unboundid.ldap.protocol.CompareRequestProtocolOp; 039import com.unboundid.ldap.protocol.CompareResponseProtocolOp; 040import com.unboundid.ldap.protocol.DeleteRequestProtocolOp; 041import com.unboundid.ldap.protocol.DeleteResponseProtocolOp; 042import com.unboundid.ldap.protocol.ExtendedRequestProtocolOp; 043import com.unboundid.ldap.protocol.ExtendedResponseProtocolOp; 044import com.unboundid.ldap.protocol.IntermediateResponseProtocolOp; 045import com.unboundid.ldap.protocol.LDAPMessage; 046import com.unboundid.ldap.protocol.ModifyRequestProtocolOp; 047import com.unboundid.ldap.protocol.ModifyResponseProtocolOp; 048import com.unboundid.ldap.protocol.ModifyDNRequestProtocolOp; 049import com.unboundid.ldap.protocol.ModifyDNResponseProtocolOp; 050import com.unboundid.ldap.protocol.SearchRequestProtocolOp; 051import com.unboundid.ldap.protocol.SearchResultDoneProtocolOp; 052import com.unboundid.ldap.protocol.SearchResultEntryProtocolOp; 053import com.unboundid.ldap.protocol.SearchResultReferenceProtocolOp; 054import com.unboundid.ldap.protocol.UnbindRequestProtocolOp; 055import com.unboundid.ldap.sdk.Control; 056import com.unboundid.ldap.sdk.Entry; 057import com.unboundid.ldap.sdk.LDAPException; 058import com.unboundid.ldap.sdk.ResultCode; 059import com.unboundid.ldif.LDIFModifyChangeRecord; 060import com.unboundid.util.NotMutable; 061import com.unboundid.util.ObjectPair; 062import com.unboundid.util.ThreadSafety; 063import com.unboundid.util.ThreadSafetyLevel; 064import com.unboundid.util.Validator; 065 066import static com.unboundid.util.StaticUtils.*; 067 068 069 070/** 071 * This class provides a request handler that may be used to write detailed 072 * information about the contents of all requests and responses that pass 073 * through it. It will be also be associated with another request handler that 074 * will actually be used to handle the request. 075 */ 076@NotMutable() 077@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 078public final class LDAPDebuggerRequestHandler 079 extends LDAPListenerRequestHandler 080 implements IntermediateResponseTransformer, SearchEntryTransformer, 081 SearchReferenceTransformer 082{ 083 /** 084 * The thread-local buffers that will be used to hold the log messages as they 085 * are being generated. 086 */ 087 private static final ThreadLocal<StringBuilder> BUFFERS = 088 new ThreadLocal<StringBuilder>(); 089 090 091 092 // The log handler that will be used to log the messages. 093 private final Handler logHandler; 094 095 // The request handler that actually will be used to process any requests 096 // received. 097 private final LDAPListenerRequestHandler requestHandler; 098 099 // The header string that will be used before each message. 100 private final String headerString; 101 102 103 104 /** 105 * Creates a new LDAP debugger request handler that will write detailed 106 * information about the contents of all requests and responses that pass 107 * through it using the provided log handler, and will process client requests 108 * using the provided request handler. 109 * 110 * @param logHandler The log handler that will be used to write detailed 111 * information about requests and responses. Note 112 * that all messages will be logged at the INFO level. 113 * It must not be {@code null}. Note that the log 114 * handler will not be automatically closed when the 115 * associated listener is shut down. 116 * @param requestHandler The request handler that will actually be used to 117 * process any requests received. It must not be 118 * {@code null}. 119 */ 120 public LDAPDebuggerRequestHandler(final Handler logHandler, 121 final LDAPListenerRequestHandler requestHandler) 122 { 123 Validator.ensureNotNull(logHandler, requestHandler); 124 125 this.logHandler = logHandler; 126 this.requestHandler = requestHandler; 127 128 headerString = null; 129 } 130 131 132 133 /** 134 * Creates a new LDAP debugger request handler that will write detailed 135 * information about the contents of all requests and responses that pass 136 * through it using the provided log handler, and will process client requests 137 * using the provided request handler. 138 * 139 * @param logHandler The log handler that will be used to write detailed 140 * information about requests and responses. Note 141 * that all messages will be logged at the INFO level. 142 * It must not be {@code null}. 143 * @param requestHandler The request handler that will actually be used to 144 * process any requests received. It must not be 145 * {@code null}. 146 * @param headerString The string that should be given as the first line 147 * of every log message. 148 */ 149 private LDAPDebuggerRequestHandler(final Handler logHandler, 150 final LDAPListenerRequestHandler requestHandler, 151 final String headerString) 152 { 153 Validator.ensureNotNull(logHandler, requestHandler); 154 155 this.logHandler = logHandler; 156 this.requestHandler = requestHandler; 157 this.headerString = headerString; 158 } 159 160 161 162 /** 163 * {@inheritDoc} 164 */ 165 @Override() 166 public LDAPDebuggerRequestHandler newInstance( 167 final LDAPListenerClientConnection connection) 168 throws LDAPException 169 { 170 final StringBuilder b = getBuffer(); 171 final Socket s = connection.getSocket(); 172 b.append("conn="); 173 b.append(connection.getConnectionID()); 174 b.append(" from=\""); 175 b.append(s.getInetAddress().getHostAddress()); 176 b.append(':'); 177 b.append(s.getPort()); 178 b.append("\" to=\""); 179 b.append(s.getLocalAddress().getHostAddress()); 180 b.append(':'); 181 b.append(s.getLocalPort()); 182 b.append('"'); 183 b.append(EOL); 184 185 final String header = b.toString(); 186 187 final LDAPDebuggerRequestHandler h = new LDAPDebuggerRequestHandler( 188 logHandler, requestHandler.newInstance(connection), header); 189 190 connection.addIntermediateResponseTransformer(h); 191 connection.addSearchEntryTransformer(h); 192 connection.addSearchReferenceTransformer(h); 193 194 logHandler.publish(new LogRecord(Level.INFO, "CONNECT " + header)); 195 196 return h; 197 } 198 199 200 201 /** 202 * {@inheritDoc} 203 */ 204 @Override() 205 public void closeInstance() 206 { 207 final StringBuilder b = getBuffer(); 208 b.append("DISCONNECT "); 209 b.append(headerString); 210 211 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 212 213 requestHandler.closeInstance(); 214 } 215 216 217 218 /** 219 * {@inheritDoc} 220 */ 221 @Override() 222 public void processAbandonRequest(final int messageID, 223 final AbandonRequestProtocolOp request, 224 final List<Control> controls) 225 { 226 final StringBuilder b = getBuffer(); 227 appendHeader(b, messageID); 228 229 b.append(" Abandon Request Protocol Op:").append(EOL); 230 b.append(" ID to Abandon: ").append(request.getIDToAbandon()). 231 append(EOL); 232 233 appendControls(b, controls); 234 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 235 236 requestHandler.processAbandonRequest(messageID, request, controls); 237 } 238 239 240 241 /** 242 * {@inheritDoc} 243 */ 244 @Override() 245 public LDAPMessage processAddRequest(final int messageID, 246 final AddRequestProtocolOp request, 247 final List<Control> controls) 248 { 249 final StringBuilder b = getBuffer(); 250 appendHeader(b, messageID); 251 252 b.append(" Add Request Protocol Op:").append(EOL); 253 254 final Entry e = new Entry(request.getDN(), request.getAttributes()); 255 final String[] ldifLines = e.toLDIF(80); 256 for (final String line : ldifLines) 257 { 258 b.append(" ").append(line).append(EOL); 259 } 260 261 appendControls(b, controls); 262 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 263 264 final LDAPMessage responseMessage = requestHandler.processAddRequest( 265 messageID, request, controls); 266 267 b.setLength(0); 268 appendHeader(b, responseMessage.getMessageID()); 269 b.append(" Add Response Protocol Op:").append(EOL); 270 271 final AddResponseProtocolOp protocolOp = 272 responseMessage.getAddResponseProtocolOp(); 273 appendResponse(b, protocolOp.getResultCode(), 274 protocolOp.getDiagnosticMessage(), 275 protocolOp.getMatchedDN(), protocolOp.getReferralURLs()); 276 277 appendControls(b, responseMessage.getControls()); 278 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 279 280 return responseMessage; 281 } 282 283 284 285 /** 286 * {@inheritDoc} 287 */ 288 @Override() 289 public LDAPMessage processBindRequest(final int messageID, 290 final BindRequestProtocolOp request, 291 final List<Control> controls) 292 { 293 final StringBuilder b = getBuffer(); 294 appendHeader(b, messageID); 295 296 b.append(" Bind Request Protocol Op:").append(EOL); 297 b.append(" LDAP Version: ").append(request.getVersion()). 298 append(EOL); 299 b.append(" Bind DN: ").append(request.getBindDN()).append(EOL); 300 301 switch (request.getCredentialsType()) 302 { 303 case BindRequestProtocolOp.CRED_TYPE_SIMPLE: 304 b.append(" Credentials Type: SIMPLE").append(EOL); 305 b.append(" Password: "). 306 append(request.getSimplePassword()).append(EOL); 307 break; 308 309 case BindRequestProtocolOp.CRED_TYPE_SASL: 310 b.append(" Credentials Type: SASL").append(EOL); 311 b.append(" Mechanism: "). 312 append(request.getSASLMechanism()).append(EOL); 313 314 final ASN1OctetString saslCredentials = request.getSASLCredentials(); 315 if (saslCredentials != null) 316 { 317 b.append(" Encoded Credentials:"); 318 b.append(EOL); 319 toHexPlusASCII(saslCredentials.getValue(), 20, b); 320 } 321 break; 322 } 323 324 appendControls(b, controls); 325 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 326 327 final LDAPMessage responseMessage = requestHandler.processBindRequest( 328 messageID, request, controls); 329 330 b.setLength(0); 331 appendHeader(b, responseMessage.getMessageID()); 332 b.append(" Bind Response Protocol Op:").append(EOL); 333 334 final BindResponseProtocolOp protocolOp = 335 responseMessage.getBindResponseProtocolOp(); 336 appendResponse(b, protocolOp.getResultCode(), 337 protocolOp.getDiagnosticMessage(), 338 protocolOp.getMatchedDN(), protocolOp.getReferralURLs()); 339 340 final ASN1OctetString serverSASLCredentials = 341 protocolOp.getServerSASLCredentials(); 342 if (serverSASLCredentials != null) 343 { 344 b.append(" Encoded Server SASL Credentials:"); 345 b.append(EOL); 346 toHexPlusASCII(serverSASLCredentials.getValue(), 20, b); 347 } 348 349 appendControls(b, responseMessage.getControls()); 350 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 351 352 return responseMessage; 353 } 354 355 356 357 /** 358 * {@inheritDoc} 359 */ 360 @Override() 361 public LDAPMessage processCompareRequest(final int messageID, 362 final CompareRequestProtocolOp request, 363 final List<Control> controls) 364 { 365 final StringBuilder b = getBuffer(); 366 appendHeader(b, messageID); 367 368 b.append(" Compare Request Protocol Op:").append(EOL); 369 b.append(" DN: ").append(request.getDN()).append(EOL); 370 b.append(" Attribute Type: ").append(request.getAttributeName()). 371 append(EOL); 372 b.append(" Assertion Value: "). 373 append(request.getAssertionValue().stringValue()).append(EOL); 374 375 appendControls(b, controls); 376 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 377 378 final LDAPMessage responseMessage = requestHandler.processCompareRequest( 379 messageID, request, controls); 380 381 b.setLength(0); 382 appendHeader(b, responseMessage.getMessageID()); 383 b.append(" Compare Response Protocol Op:").append(EOL); 384 385 final CompareResponseProtocolOp protocolOp = 386 responseMessage.getCompareResponseProtocolOp(); 387 appendResponse(b, protocolOp.getResultCode(), 388 protocolOp.getDiagnosticMessage(), 389 protocolOp.getMatchedDN(), protocolOp.getReferralURLs()); 390 391 appendControls(b, responseMessage.getControls()); 392 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 393 394 return responseMessage; 395 } 396 397 398 399 /** 400 * {@inheritDoc} 401 */ 402 @Override() 403 public LDAPMessage processDeleteRequest(final int messageID, 404 final DeleteRequestProtocolOp request, 405 final List<Control> controls) 406 { 407 final StringBuilder b = getBuffer(); 408 appendHeader(b, messageID); 409 410 b.append(" Delete Request Protocol Op:").append(EOL); 411 b.append(" DN: ").append(request.getDN()).append(EOL); 412 413 appendControls(b, controls); 414 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 415 416 final LDAPMessage responseMessage = requestHandler.processDeleteRequest( 417 messageID, request, controls); 418 419 b.setLength(0); 420 appendHeader(b, responseMessage.getMessageID()); 421 b.append(" Delete Response Protocol Op:").append(EOL); 422 423 final DeleteResponseProtocolOp protocolOp = 424 responseMessage.getDeleteResponseProtocolOp(); 425 appendResponse(b, protocolOp.getResultCode(), 426 protocolOp.getDiagnosticMessage(), 427 protocolOp.getMatchedDN(), protocolOp.getReferralURLs()); 428 429 appendControls(b, responseMessage.getControls()); 430 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 431 432 return responseMessage; 433 } 434 435 436 437 /** 438 * {@inheritDoc} 439 */ 440 @Override() 441 public LDAPMessage processExtendedRequest(final int messageID, 442 final ExtendedRequestProtocolOp request, 443 final List<Control> controls) 444 { 445 final StringBuilder b = getBuffer(); 446 appendHeader(b, messageID); 447 448 b.append(" Extended Request Protocol Op:").append(EOL); 449 b.append(" Request OID: ").append(request.getOID()).append(EOL); 450 451 final ASN1OctetString requestValue = request.getValue(); 452 if (requestValue != null) 453 { 454 b.append(" Encoded Request Value:"); 455 b.append(EOL); 456 toHexPlusASCII(requestValue.getValue(), 15, b); 457 } 458 459 appendControls(b, controls); 460 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 461 462 final LDAPMessage responseMessage = requestHandler.processExtendedRequest( 463 messageID, request, controls); 464 465 b.setLength(0); 466 appendHeader(b, responseMessage.getMessageID()); 467 b.append(" Extended Response Protocol Op:").append(EOL); 468 469 final ExtendedResponseProtocolOp protocolOp = 470 responseMessage.getExtendedResponseProtocolOp(); 471 appendResponse(b, protocolOp.getResultCode(), 472 protocolOp.getDiagnosticMessage(), 473 protocolOp.getMatchedDN(), protocolOp.getReferralURLs()); 474 475 final String responseOID = protocolOp.getResponseOID(); 476 if (responseOID != null) 477 { 478 b.append(" Response OID: ").append(responseOID).append(EOL); 479 } 480 481 final ASN1OctetString responseValue = protocolOp.getResponseValue(); 482 if (responseValue != null) 483 { 484 b.append(" Encoded Response Value:"); 485 b.append(EOL); 486 toHexPlusASCII(responseValue.getValue(), 15, b); 487 } 488 489 appendControls(b, responseMessage.getControls()); 490 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 491 492 return responseMessage; 493 } 494 495 496 497 /** 498 * {@inheritDoc} 499 */ 500 @Override() 501 public LDAPMessage processModifyRequest(final int messageID, 502 final ModifyRequestProtocolOp request, 503 final List<Control> controls) 504 { 505 final StringBuilder b = getBuffer(); 506 appendHeader(b, messageID); 507 508 b.append(" Modify Request Protocol Op:").append(EOL); 509 510 final LDIFModifyChangeRecord changeRecord = 511 new LDIFModifyChangeRecord(request.getDN(), 512 request.getModifications()); 513 final String[] ldifLines = changeRecord.toLDIF(80); 514 for (final String line : ldifLines) 515 { 516 b.append(" ").append(line).append(EOL); 517 } 518 519 appendControls(b, controls); 520 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 521 522 final LDAPMessage responseMessage = requestHandler.processModifyRequest( 523 messageID, request, controls); 524 525 b.setLength(0); 526 appendHeader(b, responseMessage.getMessageID()); 527 b.append(" Modify Response Protocol Op:").append(EOL); 528 529 final ModifyResponseProtocolOp protocolOp = 530 responseMessage.getModifyResponseProtocolOp(); 531 appendResponse(b, protocolOp.getResultCode(), 532 protocolOp.getDiagnosticMessage(), 533 protocolOp.getMatchedDN(), protocolOp.getReferralURLs()); 534 535 appendControls(b, responseMessage.getControls()); 536 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 537 538 return responseMessage; 539 } 540 541 542 543 /** 544 * {@inheritDoc} 545 */ 546 @Override() 547 public LDAPMessage processModifyDNRequest(final int messageID, 548 final ModifyDNRequestProtocolOp request, 549 final List<Control> controls) 550 { 551 final StringBuilder b = getBuffer(); 552 appendHeader(b, messageID); 553 554 b.append(" Modify DN Request Protocol Op:").append(EOL); 555 b.append(" DN: ").append(request.getDN()).append(EOL); 556 b.append(" New RDN: ").append(request.getNewRDN()).append(EOL); 557 b.append(" Delete Old RDN: ").append(request.deleteOldRDN()). 558 append(EOL); 559 560 final String newSuperior = request.getNewSuperiorDN(); 561 if (newSuperior != null) 562 { 563 b.append(" New Superior DN: ").append(newSuperior).append(EOL); 564 } 565 566 appendControls(b, controls); 567 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 568 569 final LDAPMessage responseMessage = requestHandler.processModifyDNRequest( 570 messageID, request, controls); 571 572 b.setLength(0); 573 appendHeader(b, responseMessage.getMessageID()); 574 b.append(" Modify DN Response Protocol Op:").append(EOL); 575 576 final ModifyDNResponseProtocolOp protocolOp = 577 responseMessage.getModifyDNResponseProtocolOp(); 578 appendResponse(b, protocolOp.getResultCode(), 579 protocolOp.getDiagnosticMessage(), 580 protocolOp.getMatchedDN(), protocolOp.getReferralURLs()); 581 582 appendControls(b, responseMessage.getControls()); 583 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 584 585 return responseMessage; 586 } 587 588 589 590 /** 591 * {@inheritDoc} 592 */ 593 @Override() 594 public LDAPMessage processSearchRequest(final int messageID, 595 final SearchRequestProtocolOp request, 596 final List<Control> controls) 597 { 598 final StringBuilder b = getBuffer(); 599 appendHeader(b, messageID); 600 601 b.append(" Search Request Protocol Op:").append(EOL); 602 b.append(" Base DN: ").append(request.getBaseDN()).append(EOL); 603 b.append(" Scope: ").append(request.getScope()).append(EOL); 604 b.append(" Dereference Policy: "). 605 append(request.getDerefPolicy()).append(EOL); 606 b.append(" Size Limit: ").append(request.getSizeLimit()). 607 append(EOL); 608 b.append(" Time Limit: ").append(request.getSizeLimit()). 609 append(EOL); 610 b.append(" Types Only: ").append(request.typesOnly()).append(EOL); 611 b.append(" Filter: "); 612 request.getFilter().toString(b); 613 b.append(EOL); 614 615 final List<String> attributes = request.getAttributes(); 616 if (! attributes.isEmpty()) 617 { 618 b.append(" Requested Attributes:").append(EOL); 619 for (final String attr : attributes) 620 { 621 b.append(" ").append(attr).append(EOL); 622 } 623 } 624 625 appendControls(b, controls); 626 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 627 628 final LDAPMessage responseMessage = requestHandler.processSearchRequest( 629 messageID, request, controls); 630 631 b.setLength(0); 632 appendHeader(b, responseMessage.getMessageID()); 633 b.append(" Search Result Done Protocol Op:").append(EOL); 634 635 final SearchResultDoneProtocolOp protocolOp = 636 responseMessage.getSearchResultDoneProtocolOp(); 637 appendResponse(b, protocolOp.getResultCode(), 638 protocolOp.getDiagnosticMessage(), 639 protocolOp.getMatchedDN(), protocolOp.getReferralURLs()); 640 641 appendControls(b, responseMessage.getControls()); 642 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 643 644 return responseMessage; 645 } 646 647 648 649 /** 650 * {@inheritDoc} 651 */ 652 @Override() 653 public void processUnbindRequest(final int messageID, 654 final UnbindRequestProtocolOp request, 655 final List<Control> controls) 656 { 657 final StringBuilder b = getBuffer(); 658 appendHeader(b, messageID); 659 660 b.append(" Unbind Request Protocol Op:").append(EOL); 661 662 appendControls(b, controls); 663 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 664 665 requestHandler.processUnbindRequest(messageID, request, controls); 666 } 667 668 669 670 /** 671 * Retrieves a {@code StringBuilder} that may be used to generate a log 672 * message. 673 * 674 * @return A {@code StringBuilder} containing the LDAP message header. 675 */ 676 private static StringBuilder getBuffer() 677 { 678 StringBuilder b = BUFFERS.get(); 679 if (b == null) 680 { 681 b = new StringBuilder(); 682 BUFFERS.set(b); 683 } 684 else 685 { 686 b.setLength(0); 687 } 688 689 return b; 690 } 691 692 693 694 /** 695 * Appends an LDAP message header to the provided buffer. 696 * 697 * @param b The buffer to which to write the header. 698 * @param messageID The message ID for the LDAP message. 699 */ 700 private void appendHeader(final StringBuilder b, final int messageID) 701 { 702 b.append(headerString); 703 b.append("LDAP Message:").append(EOL); 704 b.append(" Message ID: ").append(messageID).append(EOL); 705 } 706 707 708 709 /** 710 * Appends information about an LDAP response to the given buffer. 711 * 712 * @param b The buffer to which to append the information. 713 * @param resultCode The result code for the response. 714 * @param diagnosticMessage The diagnostic message for the response, if any. 715 * @param matchedDN The matched DN for the response, if any. 716 * @param referralURLs The referral URLs for the response, if any. 717 */ 718 private static void appendResponse(final StringBuilder b, 719 final int resultCode, 720 final String diagnosticMessage, 721 final String matchedDN, 722 final List<String> referralURLs) 723 { 724 b.append(" Result Code: ").append(ResultCode.valueOf(resultCode)). 725 append(EOL); 726 727 if (diagnosticMessage != null) 728 { 729 b.append(" Diagnostic Message: ").append(diagnosticMessage). 730 append(EOL); 731 } 732 733 if (matchedDN != null) 734 { 735 b.append(" Matched DN: ").append(matchedDN).append(EOL); 736 } 737 738 if (! referralURLs.isEmpty()) 739 { 740 b.append(" Referral URLs:").append(EOL); 741 for (final String url : referralURLs) 742 { 743 b.append(" ").append(url).append(EOL); 744 } 745 } 746 } 747 748 749 750 /** 751 * Appends information about the provided set of controls to the given buffer. 752 * A trailing EOL will also be appended. 753 * 754 * @param b The buffer to which to append the control information. 755 * @param controls The set of controls to be appended to the buffer. 756 */ 757 private static void appendControls(final StringBuilder b, 758 final List<Control> controls) 759 { 760 if (! controls.isEmpty()) 761 { 762 b.append(" Controls:").append(EOL); 763 764 int index = 1; 765 for (final Control c : controls) 766 { 767 b.append(" Control "); 768 b.append(index++); 769 b.append(EOL); 770 b.append(" OID: "); 771 b.append(c.getOID()); 772 b.append(EOL); 773 b.append(" Is Critical: "); 774 b.append(c.isCritical()); 775 b.append(EOL); 776 777 final ASN1OctetString value = c.getValue(); 778 if ((value != null) && (value.getValueLength() > 0)) 779 { 780 b.append(" Encoded Value:"); 781 b.append(EOL); 782 toHexPlusASCII(value.getValue(), 20, b); 783 } 784 785 // If it is a subclass of Control rather than just a generic one, then 786 // it might have a useful toString representation, so provide it. 787 if (! c.getClass().getName().equals(Control.class.getName())) 788 { 789 b.append(" String Representation: "); 790 c.toString(b); 791 b.append(EOL); 792 } 793 } 794 } 795 } 796 797 798 799 /** 800 * Appends information about the provided set of controls to the given buffer. 801 * 802 * @param b The buffer to which to append the control information. 803 * @param controls The set of controls to be appended to the buffer. 804 */ 805 private static void appendControls(final StringBuilder b, 806 final Control[] controls) 807 { 808 appendControls(b, Arrays.asList(controls)); 809 } 810 811 812 813 /** 814 * {@inheritDoc} 815 */ 816 public ObjectPair<IntermediateResponseProtocolOp,Control[]> 817 transformIntermediateResponse(final int messageID, 818 final IntermediateResponseProtocolOp response, 819 final Control[] controls) 820 { 821 final StringBuilder b = getBuffer(); 822 appendHeader(b, messageID); 823 824 b.append(" Intermediate Response Protocol Op:").append(EOL); 825 826 final String oid = response.getOID(); 827 if (oid != null) 828 { 829 b.append(" OID: ").append(oid).append(EOL); 830 } 831 832 final ASN1OctetString value = response.getValue(); 833 if (value != null) 834 { 835 b.append(" Encoded Value:"); 836 b.append(EOL); 837 toHexPlusASCII(value.getValue(), 15, b); 838 } 839 840 appendControls(b, controls); 841 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 842 843 return new ObjectPair<IntermediateResponseProtocolOp,Control[]>(response, 844 controls); 845 } 846 847 848 849 /** 850 * {@inheritDoc} 851 */ 852 public ObjectPair<SearchResultEntryProtocolOp,Control[]> transformEntry( 853 final int messageID, final SearchResultEntryProtocolOp entry, 854 final Control[] controls) 855 { 856 final StringBuilder b = getBuffer(); 857 appendHeader(b, messageID); 858 859 b.append(" Search Result Entry Protocol Op:").append(EOL); 860 861 final Entry e = new Entry(entry.getDN(), entry.getAttributes()); 862 final String[] ldifLines = e.toLDIF(80); 863 for (final String line : ldifLines) 864 { 865 b.append(" ").append(line).append(EOL); 866 } 867 868 appendControls(b, controls); 869 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 870 871 return new ObjectPair<SearchResultEntryProtocolOp,Control[]>(entry, 872 controls); 873 } 874 875 876 877 /** 878 * {@inheritDoc} 879 */ 880 public ObjectPair<SearchResultReferenceProtocolOp,Control[]> 881 transformReference(final int messageID, 882 final SearchResultReferenceProtocolOp reference, 883 final Control[] controls) 884 { 885 final StringBuilder b = getBuffer(); 886 appendHeader(b, messageID); 887 888 b.append(" Search Result Reference Protocol Op:").append(EOL); 889 b.append(" Referral URLs:").append(EOL); 890 891 for (final String url : reference.getReferralURLs()) 892 { 893 b.append(" ").append(url).append(EOL); 894 } 895 896 appendControls(b, controls); 897 logHandler.publish(new LogRecord(Level.INFO, b.toString())); 898 899 return new ObjectPair<SearchResultReferenceProtocolOp,Control[]>(reference, 900 controls); 901 } 902}