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