001 /*
002 * Copyright 2010-2013 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2010-2013 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 */
021 package com.unboundid.ldap.listener;
022
023
024
025 import java.net.Socket;
026 import java.util.Arrays;
027 import java.util.List;
028 import java.util.logging.Handler;
029 import java.util.logging.Level;
030 import java.util.logging.LogRecord;
031
032 import com.unboundid.asn1.ASN1OctetString;
033 import com.unboundid.ldap.protocol.AbandonRequestProtocolOp;
034 import com.unboundid.ldap.protocol.AddRequestProtocolOp;
035 import com.unboundid.ldap.protocol.AddResponseProtocolOp;
036 import com.unboundid.ldap.protocol.BindRequestProtocolOp;
037 import com.unboundid.ldap.protocol.BindResponseProtocolOp;
038 import com.unboundid.ldap.protocol.CompareRequestProtocolOp;
039 import com.unboundid.ldap.protocol.CompareResponseProtocolOp;
040 import com.unboundid.ldap.protocol.DeleteRequestProtocolOp;
041 import com.unboundid.ldap.protocol.DeleteResponseProtocolOp;
042 import com.unboundid.ldap.protocol.ExtendedRequestProtocolOp;
043 import com.unboundid.ldap.protocol.ExtendedResponseProtocolOp;
044 import com.unboundid.ldap.protocol.IntermediateResponseProtocolOp;
045 import com.unboundid.ldap.protocol.LDAPMessage;
046 import com.unboundid.ldap.protocol.ModifyRequestProtocolOp;
047 import com.unboundid.ldap.protocol.ModifyResponseProtocolOp;
048 import com.unboundid.ldap.protocol.ModifyDNRequestProtocolOp;
049 import com.unboundid.ldap.protocol.ModifyDNResponseProtocolOp;
050 import com.unboundid.ldap.protocol.SearchRequestProtocolOp;
051 import com.unboundid.ldap.protocol.SearchResultDoneProtocolOp;
052 import com.unboundid.ldap.protocol.SearchResultEntryProtocolOp;
053 import com.unboundid.ldap.protocol.SearchResultReferenceProtocolOp;
054 import com.unboundid.ldap.protocol.UnbindRequestProtocolOp;
055 import com.unboundid.ldap.sdk.Control;
056 import com.unboundid.ldap.sdk.Entry;
057 import com.unboundid.ldap.sdk.LDAPException;
058 import com.unboundid.ldap.sdk.ResultCode;
059 import com.unboundid.ldif.LDIFModifyChangeRecord;
060 import com.unboundid.util.NotMutable;
061 import com.unboundid.util.ObjectPair;
062 import com.unboundid.util.ThreadSafety;
063 import com.unboundid.util.ThreadSafetyLevel;
064 import com.unboundid.util.Validator;
065
066 import 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)
078 public 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 }