001/*
002 * Copyright 2016-2019 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2016-2019 Ping Identity Corporation
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.ldap.sdk.unboundidds.tools;
022
023
024
025import java.util.ArrayList;
026import java.util.Arrays;
027import java.util.List;
028import java.util.Map;
029
030import com.unboundid.asn1.ASN1OctetString;
031import com.unboundid.ldap.sdk.Attribute;
032import com.unboundid.ldap.sdk.Control;
033import com.unboundid.ldap.sdk.Entry;
034import com.unboundid.ldap.sdk.ExtendedResult;
035import com.unboundid.ldap.sdk.LDAPException;
036import com.unboundid.ldap.sdk.LDAPResult;
037import com.unboundid.ldap.sdk.OperationType;
038import com.unboundid.ldap.sdk.ResultCode;
039import com.unboundid.ldap.sdk.SearchResult;
040import com.unboundid.ldap.sdk.SearchResultEntry;
041import com.unboundid.ldap.sdk.SearchResultReference;
042import com.unboundid.ldap.sdk.controls.AuthorizationIdentityResponseControl;
043import com.unboundid.ldap.sdk.controls.ContentSyncDoneControl;
044import com.unboundid.ldap.sdk.controls.ContentSyncStateControl;
045import com.unboundid.ldap.sdk.controls.EntryChangeNotificationControl;
046import com.unboundid.ldap.sdk.controls.PasswordExpiredControl;
047import com.unboundid.ldap.sdk.controls.PasswordExpiringControl;
048import com.unboundid.ldap.sdk.controls.PersistentSearchChangeType;
049import com.unboundid.ldap.sdk.controls.PostReadResponseControl;
050import com.unboundid.ldap.sdk.controls.PreReadResponseControl;
051import com.unboundid.ldap.sdk.controls.ServerSideSortResponseControl;
052import com.unboundid.ldap.sdk.controls.SimplePagedResultsControl;
053import com.unboundid.ldap.sdk.controls.VirtualListViewResponseControl;
054import com.unboundid.ldap.sdk.extensions.AbortedTransactionExtendedResult;
055import com.unboundid.ldap.sdk.extensions.EndTransactionExtendedResult;
056import com.unboundid.ldap.sdk.extensions.NoticeOfDisconnectionExtendedResult;
057import com.unboundid.ldap.sdk.extensions.PasswordModifyExtendedResult;
058import com.unboundid.ldap.sdk.extensions.StartTransactionExtendedResult;
059import com.unboundid.ldap.sdk.unboundidds.controls.AccountUsableResponseControl;
060import com.unboundid.ldap.sdk.unboundidds.controls.AssuredReplicationLocalLevel;
061import com.unboundid.ldap.sdk.unboundidds.controls.
062            AssuredReplicationRemoteLevel;
063import com.unboundid.ldap.sdk.unboundidds.controls.
064            AssuredReplicationServerResult;
065import com.unboundid.ldap.sdk.unboundidds.controls.
066            AssuredReplicationServerResultCode;
067import com.unboundid.ldap.sdk.unboundidds.controls.
068            AssuredReplicationResponseControl;
069import com.unboundid.ldap.sdk.unboundidds.controls.AuthenticationFailureReason;
070import com.unboundid.ldap.sdk.unboundidds.controls.
071            GetAuthorizationEntryResponseControl;
072import com.unboundid.ldap.sdk.unboundidds.controls.
073            GetBackendSetIDResponseControl;
074import com.unboundid.ldap.sdk.unboundidds.controls.
075            GetPasswordPolicyStateIssuesResponseControl;
076import com.unboundid.ldap.sdk.unboundidds.controls.GetServerIDResponseControl;
077import com.unboundid.ldap.sdk.unboundidds.controls.
078            GetUserResourceLimitsResponseControl;
079import com.unboundid.ldap.sdk.unboundidds.controls.
080            IntermediateClientResponseControl;
081import com.unboundid.ldap.sdk.unboundidds.controls.
082            IntermediateClientResponseValue;
083import com.unboundid.ldap.sdk.unboundidds.controls.JoinedEntry;
084import com.unboundid.ldap.sdk.unboundidds.controls.JoinResultControl;
085import com.unboundid.ldap.sdk.unboundidds.controls.
086            MatchingEntryCountResponseControl;
087import com.unboundid.ldap.sdk.unboundidds.controls.PasswordPolicyErrorType;
088import com.unboundid.ldap.sdk.unboundidds.controls.
089            PasswordPolicyResponseControl;
090import com.unboundid.ldap.sdk.unboundidds.controls.PasswordPolicyWarningType;
091import com.unboundid.ldap.sdk.unboundidds.controls.
092            PasswordQualityRequirementValidationResult;
093import com.unboundid.ldap.sdk.unboundidds.controls.
094            PasswordValidationDetailsResponseControl;
095import com.unboundid.ldap.sdk.unboundidds.controls.SoftDeleteResponseControl;
096import com.unboundid.ldap.sdk.unboundidds.controls.
097            TransactionSettingsResponseControl;
098import com.unboundid.ldap.sdk.unboundidds.controls.UniquenessResponseControl;
099import com.unboundid.ldap.sdk.unboundidds.extensions.MultiUpdateChangesApplied;
100import com.unboundid.ldap.sdk.unboundidds.extensions.MultiUpdateExtendedResult;
101import com.unboundid.ldap.sdk.unboundidds.extensions.
102            PasswordPolicyStateAccountUsabilityError;
103import com.unboundid.ldap.sdk.unboundidds.extensions.
104            PasswordPolicyStateAccountUsabilityNotice;
105import com.unboundid.ldap.sdk.unboundidds.extensions.
106            PasswordPolicyStateAccountUsabilityWarning;
107import com.unboundid.ldap.sdk.unboundidds.extensions.PasswordQualityRequirement;
108import com.unboundid.util.Debug;
109import com.unboundid.util.ObjectPair;
110import com.unboundid.util.StaticUtils;
111import com.unboundid.util.ThreadSafety;
112import com.unboundid.util.ThreadSafetyLevel;
113
114import static com.unboundid.ldap.sdk.unboundidds.tools.ToolMessages.*;
115
116
117
118/**
119 * This class provides a set of utility methods for formatting operation
120 * results.
121 * <BR>
122 * <BLOCKQUOTE>
123 *   <B>NOTE:</B>  This class, and other classes within the
124 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
125 *   supported for use against Ping Identity, UnboundID, and
126 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
127 *   for proprietary functionality or for external specifications that are not
128 *   considered stable or mature enough to be guaranteed to work in an
129 *   interoperable way with other types of LDAP servers.
130 * </BLOCKQUOTE>
131 */
132@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
133public final class ResultUtils
134{
135  /**
136   * Ensures that this utility class can't be instantiated.
137   */
138  private ResultUtils()
139  {
140    // No implementation required.
141  }
142
143
144
145  /**
146   * Retrieves a list of strings that comprise a formatted representation of the
147   * provided result.
148   *
149   * @param  result    The result to be formatted.
150   * @param  comment   Indicates whether to prefix each line with an octothorpe
151   *                   to indicate that it is a comment.
152   * @param  indent    The number of spaces to indent each line.
153   * @param  maxWidth  The maximum length of each line in characters, including
154   *                   the comment prefix and indent.
155   *
156   * @return  A list of strings that comprise a formatted representation of the
157   *          provided result.
158   */
159  public static List<String> formatResult(final LDAPResult result,
160                                          final boolean comment,
161                                          final int indent, final int maxWidth)
162  {
163    final ArrayList<String> lines = new ArrayList<>(10);
164    formatResult(lines, result, comment, false, indent, maxWidth);
165    return lines;
166  }
167
168
169
170  /**
171   * Retrieves a list of strings that comprise a formatted representation of the
172   * result encapsulated by the provided exception.
173   *
174   * @param  ldapException  The exception to use to obtain the result to format.
175   * @param  comment        Indicates whether to prefix each line with an
176   *                        octothorpe to indicate that it is a comment.
177   * @param  indent         The number of spaces to indent each line.
178   * @param  maxWidth       The maximum length of each line in characters,
179   *                        including the comment prefix and indent.
180   *
181   * @return  A list of strings that comprise a formatted representation of the
182   *          result encapsulated by the provided exception.
183   */
184  public static List<String> formatResult(final LDAPException ldapException,
185                                          final boolean comment,
186                                          final int indent, final int maxWidth)
187  {
188    return formatResult(ldapException.toLDAPResult(), comment, indent,
189         maxWidth);
190  }
191
192
193
194  /**
195   * Adds a multi-line string representation of the provided result to the
196   * given list.
197   *
198   * @param  lines     The list to which the lines should be added.
199   * @param  result    The result to be formatted.
200   * @param  comment   Indicates whether to prefix each line with an octothorpe
201   *                   to indicate that it is a comment.
202   * @param  inTxn     Indicates whether the operation is part of an active
203   *                   transaction.
204   * @param  indent    The number of spaces to indent each line.
205   * @param  maxWidth  The maximum length of each line in characters, including
206   *                   the comment prefix and indent.
207   */
208  public static void formatResult(final List<String> lines,
209                                  final LDAPResult result,
210                                  final boolean comment, final boolean inTxn,
211                                  final int indent, final int maxWidth)
212  {
213    formatResult(lines, result, inTxn, createPrefix(comment, indent), maxWidth);
214  }
215
216
217
218  /**
219   * Adds a multi-line string representation of the provided result to the
220   * given list.
221   *
222   * @param  lines     The list to which the lines should be added.
223   * @param  result    The result to be formatted.
224   * @param  inTxn     Indicates whether the operation is part of an active
225   *                   transaction.
226   * @param  prefix    The prefix to use for each line.
227   * @param  maxWidth  The maximum length of each line in characters, including
228   *                   the comment prefix and indent.
229   */
230  private static void formatResult(final List<String> lines,
231                                   final LDAPResult result, final boolean inTxn,
232                                   final String prefix, final int maxWidth)
233  {
234    // Format the result code.  If it's a success result but the operation was
235    // part of a transaction, then indicate that no change has actually been
236    // made yet.
237    final ResultCode resultCode = result.getResultCode();
238    wrap(lines, INFO_RESULT_UTILS_RESULT_CODE.get(String.valueOf(resultCode)),
239         prefix, maxWidth);
240    if (inTxn && (resultCode == ResultCode.SUCCESS))
241    {
242      wrap(lines, INFO_RESULT_UTILS_SUCCESS_WITH_TXN.get(), prefix, maxWidth);
243    }
244
245
246    // Format the diagnostic message, if there is one.
247    final String diagnosticMessage = result.getDiagnosticMessage();
248    if (diagnosticMessage != null)
249    {
250      wrap(lines, INFO_RESULT_UTILS_DIAGNOSTIC_MESSAGE.get(diagnosticMessage),
251           prefix, maxWidth);
252    }
253
254
255    // Format the matched DN, if there is one.
256    final String matchedDN = result.getMatchedDN();
257    if (matchedDN != null)
258    {
259      wrap(lines, INFO_RESULT_UTILS_MATCHED_DN.get(matchedDN), prefix,
260           maxWidth);
261    }
262
263
264    // If there are any referral URLs, then display them.
265    final String[] referralURLs = result.getReferralURLs();
266    if (referralURLs != null)
267    {
268      for (final String referralURL : referralURLs)
269      {
270        wrap(lines, INFO_RESULT_UTILS_REFERRAL_URL.get(referralURL), prefix,
271             maxWidth);
272      }
273    }
274
275
276    if (result instanceof SearchResult)
277    {
278      final SearchResult searchResult = (SearchResult) result;
279
280      // We'll always display the search entry count if we know it.
281      final int numEntries = searchResult.getEntryCount();
282      if (numEntries >= 0)
283      {
284        wrap(lines, INFO_RESULT_UTILS_NUM_SEARCH_ENTRIES.get(numEntries),
285             prefix, maxWidth);
286      }
287
288      // We'll only display the search reference count if it's greater than
289      // zero.
290      final int numReferences = searchResult.getReferenceCount();
291      if (numReferences > 0)
292      {
293        wrap(lines, INFO_RESULT_UTILS_NUM_SEARCH_REFERENCES.get(numReferences),
294             prefix, maxWidth);
295      }
296    }
297    else if (result instanceof StartTransactionExtendedResult)
298    {
299      final StartTransactionExtendedResult startTxnResult =
300           (StartTransactionExtendedResult) result;
301      final ASN1OctetString txnID = startTxnResult.getTransactionID();
302      if (txnID != null)
303      {
304        if (StaticUtils.isPrintableString(txnID.getValue()))
305        {
306          wrap(lines,
307               INFO_RESULT_UTILS_START_TXN_RESULT_TXN_ID.get(
308                    txnID.stringValue()),
309               prefix, maxWidth);
310        }
311        else
312        {
313          wrap(lines,
314               INFO_RESULT_UTILS_START_TXN_RESULT_TXN_ID.get(
315                    "0x" + StaticUtils.toHex(txnID.getValue())),
316               prefix, maxWidth);
317        }
318      }
319    }
320    else if (result instanceof EndTransactionExtendedResult)
321    {
322      final EndTransactionExtendedResult endTxnResult =
323           (EndTransactionExtendedResult) result;
324      final int failedOpMessageID = endTxnResult.getFailedOpMessageID();
325      if (failedOpMessageID > 0)
326      {
327        wrap(lines,
328             INFO_RESULT_UTILS_END_TXN_RESULT_FAILED_MSG_ID.get(
329                  failedOpMessageID),
330             prefix, maxWidth);
331      }
332
333      final Map<Integer,Control[]> controls =
334           endTxnResult.getOperationResponseControls();
335      if (controls != null)
336      {
337        for (final Map.Entry<Integer,Control[]> e : controls.entrySet())
338        {
339          for (final Control c : e.getValue())
340          {
341            wrap(lines,
342                 INFO_RESULT_UTILS_END_TXN_RESULT_OP_CONTROL.get(e.getKey()),
343                 prefix, maxWidth);
344            formatResponseControl(lines, c, prefix + "     ", maxWidth);
345          }
346        }
347      }
348    }
349    else if (result instanceof MultiUpdateExtendedResult)
350    {
351      final MultiUpdateExtendedResult multiUpdateResult =
352           (MultiUpdateExtendedResult) result;
353
354      final MultiUpdateChangesApplied changesApplied =
355           multiUpdateResult.getChangesApplied();
356      if (changesApplied != null)
357      {
358        wrap(lines,
359             INFO_RESULT_UTILS_MULTI_UPDATE_CHANGES_APPLIED.get(
360                  changesApplied.name()),
361             prefix, maxWidth);
362      }
363
364      final List<ObjectPair<OperationType,LDAPResult>> multiUpdateResults =
365           multiUpdateResult.getResults();
366      if (multiUpdateResults != null)
367      {
368        for (final ObjectPair<OperationType,LDAPResult> p : multiUpdateResults)
369        {
370          wrap(lines,
371               INFO_RESULT_UTILS_MULTI_UPDATE_RESULT_HEADER.get(
372                    p.getFirst().name()),
373               prefix, maxWidth);
374          formatResult(lines, p.getSecond(), false, prefix + "     ", maxWidth);
375        }
376      }
377    }
378    else if (result instanceof PasswordModifyExtendedResult)
379    {
380      final PasswordModifyExtendedResult passwordModifyResult =
381           (PasswordModifyExtendedResult) result;
382
383      final String generatedPassword =
384           passwordModifyResult.getGeneratedPassword();
385      if (generatedPassword != null)
386      {
387        wrap(lines,
388             INFO_RESULT_UTILS_PASSWORD_MODIFY_RESULT_GENERATED_PW.get(
389                  generatedPassword),
390             prefix, maxWidth);
391      }
392    }
393    else if (result instanceof ExtendedResult)
394    {
395      final ExtendedResult extendedResult = (ExtendedResult) result;
396      final String oid = ((ExtendedResult) result).getOID();
397      if (oid != null)
398      {
399        wrap(lines, INFO_RESULT_UTILS_RESPONSE_EXTOP_OID.get(oid), prefix,
400             maxWidth);
401      }
402
403      final ASN1OctetString value = extendedResult.getValue();
404      if ((value != null) && (value.getValueLength() > 0))
405      {
406        wrap(lines, INFO_RESULT_UTILS_RESPONSE_EXTOP_RAW_VALUE_HEADER.get(),
407             prefix, maxWidth);
408
409        // We'll ignore the maximum width for this portion of the output.
410        for (final String line :
411             StaticUtils.stringToLines(
412                  StaticUtils.toHexPlusASCII(value.getValue(), 0)))
413        {
414          lines.add(prefix + "     " + line);
415        }
416      }
417    }
418
419
420    // If there are any controls, then display them.  We'll interpret any
421    // controls that we can, but will fall back to a general display for any
422    // that we don't recognize or can't parse.
423    final Control[] controls = result.getResponseControls();
424    if (controls != null)
425    {
426      for (final Control c : controls)
427      {
428        formatResponseControl(lines, c, prefix, maxWidth);
429      }
430    }
431  }
432
433
434
435  /**
436   * Updates the provided list with an LDIF representation of the provided
437   * search result entry to the given list, preceded by comments about any
438   * controls that may be included with the entry.
439   *
440   * @param  lines     The list to which the formatted representation will be
441   *                   added.
442   * @param  entry     The entry to be formatted.
443   * @param  maxWidth  The maximum length of each line in characters, including
444   *                   any comment prefix and indent.
445   */
446  public static void formatSearchResultEntry(final List<String> lines,
447                                             final SearchResultEntry entry,
448                                             final int maxWidth)
449  {
450    for (final Control c : entry.getControls())
451    {
452      formatResponseControl(lines, c, true, 0, maxWidth);
453    }
454
455    lines.addAll(Arrays.asList(entry.toLDIF(maxWidth)));
456  }
457
458
459
460  /**
461   * Updates the provided with with a string representation of the provided
462   * search result reference.  The information will be written as LDIF
463   * comments, and will include any referral URLs contained in the reference, as
464   * well as information about any associated controls.
465   *
466   * @param  lines      The list to which the formatted representation will be
467   *                    added.
468   * @param  reference  The search result reference to be formatted.
469   * @param  maxWidth   The maximum length of each line in characters, including
470   *                    any comment prefix and indent.
471   */
472  public static void formatSearchResultReference(final List<String> lines,
473                          final SearchResultReference reference,
474                          final int maxWidth)
475  {
476    wrap(lines, INFO_RESULT_UTILS_SEARCH_REFERENCE_HEADER.get(), "# ",
477         maxWidth);
478    for (final String url : reference.getReferralURLs())
479    {
480      wrap(lines, INFO_RESULT_UTILS_REFERRAL_URL.get(url), "#      ", maxWidth);
481    }
482
483    for (final Control c : reference.getControls())
484    {
485      formatResponseControl(lines, c, "#      ", maxWidth);
486    }
487  }
488
489
490
491  /**
492   * Adds a multi-line string representation of the provided unsolicited
493   * notification to the given list.
494   *
495   * @param  lines         The list to which the lines should be added.
496   * @param  notification  The unsolicited notification to be formatted.
497   * @param  comment       Indicates whether to prefix each line with an
498   *                       octothorpe to indicate that it is a comment.
499   * @param  indent        The number of spaces to indent each line.
500   * @param  maxWidth      The maximum length of each line in characters,
501   *                       including the comment prefix and indent.
502   */
503  public static void formatUnsolicitedNotification(final List<String> lines,
504                          final ExtendedResult notification,
505                          final boolean comment, final int indent,
506                          final int maxWidth)
507  {
508    final String prefix = createPrefix(comment, indent);
509    final String indentPrefix = prefix + "     ";
510
511    boolean includeRawValue = true;
512    final String oid = notification.getOID();
513    if (oid != null)
514    {
515      if (oid.equals(NoticeOfDisconnectionExtendedResult.
516           NOTICE_OF_DISCONNECTION_RESULT_OID))
517      {
518        wrap(lines, INFO_RESULT_UTILS_NOTICE_OF_DISCONNECTION_HEADER.get(),
519             prefix, maxWidth);
520        wrap(lines, INFO_RESULT_UTILS_RESPONSE_EXTOP_OID.get(oid),
521             indentPrefix, maxWidth);
522      }
523      else if (oid.equals(AbortedTransactionExtendedResult.
524           ABORTED_TRANSACTION_RESULT_OID))
525      {
526        wrap(lines, INFO_RESULT_UTILS_ABORTED_TXN_HEADER.get(), prefix,
527             maxWidth);
528        wrap(lines, INFO_RESULT_UTILS_RESPONSE_EXTOP_OID.get(oid),
529             indentPrefix, maxWidth);
530
531        try
532        {
533          final AbortedTransactionExtendedResult r =
534               new AbortedTransactionExtendedResult(notification);
535
536          final String txnID;
537          if (StaticUtils.isPrintableString(r.getTransactionID().getValue()))
538          {
539            txnID = r.getTransactionID().stringValue();
540          }
541          else
542          {
543            txnID = "0x" + StaticUtils.toHex(r.getTransactionID().getValue());
544          }
545          wrap(lines, INFO_RESULT_UTILS_TXN_ID_HEADER.get(txnID), indentPrefix,
546               maxWidth);
547          includeRawValue = false;
548        }
549        catch (final Exception e)
550        {
551          Debug.debugException(e);
552        }
553      }
554      else
555      {
556        wrap(lines, INFO_RESULT_UTILS_UNSOLICITED_NOTIFICATION_HEADER.get(),
557             prefix, maxWidth);
558        wrap(lines, INFO_RESULT_UTILS_RESPONSE_EXTOP_OID.get(oid),
559             indentPrefix, maxWidth);
560      }
561    }
562    else
563    {
564      wrap(lines, INFO_RESULT_UTILS_UNSOLICITED_NOTIFICATION_HEADER.get(),
565           prefix, maxWidth);
566    }
567
568
569    wrap(lines,
570         INFO_RESULT_UTILS_RESULT_CODE.get(
571              String.valueOf(notification.getResultCode())),
572         indentPrefix, maxWidth);
573
574    final String diagnosticMessage = notification.getDiagnosticMessage();
575    if (diagnosticMessage != null)
576    {
577      wrap(lines,
578           INFO_RESULT_UTILS_DIAGNOSTIC_MESSAGE.get(diagnosticMessage),
579           indentPrefix, maxWidth);
580    }
581
582    final String matchedDN = notification.getMatchedDN();
583    if (matchedDN != null)
584    {
585      wrap(lines, INFO_RESULT_UTILS_MATCHED_DN.get(matchedDN), indentPrefix,
586           maxWidth);
587    }
588
589    final String[] referralURLs = notification.getReferralURLs();
590    if (referralURLs != null)
591    {
592      for (final String referralURL : referralURLs)
593      {
594        wrap(lines, INFO_RESULT_UTILS_REFERRAL_URL.get(referralURL),
595             indentPrefix, maxWidth);
596      }
597    }
598
599    if (includeRawValue)
600    {
601      final ASN1OctetString value = notification.getValue();
602      if ((value != null) && (value.getValueLength() > 0))
603      {
604        wrap(lines, INFO_RESULT_UTILS_RESPONSE_EXTOP_RAW_VALUE_HEADER.get(),
605             indentPrefix, maxWidth);
606
607        // We'll ignore the maximum width for this portion of the output.
608        for (final String line :
609             StaticUtils.stringToLines(
610                  StaticUtils.toHexPlusASCII(value.getValue(), 0)))
611        {
612          lines.add(prefix + "          " + line);
613        }
614      }
615    }
616
617
618    // If there are any controls, then display them.  We'll interpret any
619    // controls that we can, but will fall back to a general display for any
620    // that we don't recognize or can't parse.
621    final Control[] controls = notification.getResponseControls();
622    if (controls != null)
623    {
624      for (final Control c : controls)
625      {
626        formatResponseControl(lines, c, comment, indent+5, maxWidth);
627      }
628    }
629  }
630
631
632
633  /**
634   * Adds a multi-line string representation of the provided result to the
635   * given list.
636   *
637   * @param  lines     The list to which the lines should be added.
638   * @param  c         The control to be formatted.
639   * @param  comment   Indicates whether to prefix each line with an octothorpe
640   *                   to indicate that it is a comment.
641   * @param  indent    The number of spaces to indent each line.
642   * @param  maxWidth  The maximum length of each line in characters, including
643   *                   the comment prefix and indent.
644   */
645  public static void formatResponseControl(final List<String> lines,
646                                           final Control c,
647                                           final boolean comment,
648                                           final int indent, final int maxWidth)
649  {
650    // Generate a prefix that will be used for every line.
651    final StringBuilder buffer = new StringBuilder(indent + 2);
652    if (comment)
653    {
654      buffer.append("# ");
655    }
656    for (int i=0; i < indent; i++)
657    {
658      buffer.append(' ');
659    }
660    final String prefix = buffer.toString();
661
662
663    formatResponseControl(lines, c, prefix, maxWidth);
664  }
665
666
667
668  /**
669   * Adds a multi-line string representation of the provided control to the
670   * given list.
671   *
672   * @param  lines     The list to which the lines should be added.
673   * @param  c         The control to be formatted.
674   * @param  prefix    The prefix to use for each line.
675   * @param  maxWidth  The maximum length of each line in characters, including
676   *                   the comment prefix and indent.
677   */
678  private static void formatResponseControl(final List<String> lines,
679                                            final Control c,
680                                            final String prefix,
681                                            final int maxWidth)
682  {
683    final String oid = c.getOID();
684    if (oid.equals(AuthorizationIdentityResponseControl.
685         AUTHORIZATION_IDENTITY_RESPONSE_OID))
686    {
687      addAuthorizationIdentityResponseControl(lines, c, prefix, maxWidth);
688    }
689    else if (oid.equals(ContentSyncDoneControl.SYNC_DONE_OID))
690    {
691      addContentSyncDoneControl(lines, c, prefix, maxWidth);
692    }
693    else if (oid.equals(ContentSyncStateControl.SYNC_STATE_OID))
694    {
695      addContentSyncStateControl(lines, c, prefix, maxWidth);
696    }
697    else if (oid.equals(EntryChangeNotificationControl.
698         ENTRY_CHANGE_NOTIFICATION_OID))
699    {
700      addEntryChangeNotificationControl(lines, c, prefix, maxWidth);
701    }
702    else if (oid.equals(PasswordExpiredControl.PASSWORD_EXPIRED_OID))
703    {
704      addPasswordExpiredControl(lines, c, prefix, maxWidth);
705    }
706    else if (oid.equals(PasswordExpiringControl.PASSWORD_EXPIRING_OID))
707    {
708      addPasswordExpiringControl(lines, c, prefix, maxWidth);
709    }
710    else if (oid.equals(PostReadResponseControl.POST_READ_RESPONSE_OID))
711    {
712      addPostReadResponseControl(lines, c, prefix, maxWidth);
713    }
714    else if (oid.equals(PreReadResponseControl.PRE_READ_RESPONSE_OID))
715    {
716      addPreReadResponseControl(lines, c, prefix, maxWidth);
717    }
718    else if (oid.equals(ServerSideSortResponseControl.
719         SERVER_SIDE_SORT_RESPONSE_OID))
720    {
721      addServerSideSortResponseControl(lines, c, prefix, maxWidth);
722    }
723    else if (oid.equals(SimplePagedResultsControl.PAGED_RESULTS_OID))
724    {
725      addSimplePagedResultsControl(lines, c, prefix, maxWidth);
726    }
727    else if (oid.equals(VirtualListViewResponseControl.
728         VIRTUAL_LIST_VIEW_RESPONSE_OID))
729    {
730      addVirtualListViewResponseControl(lines, c, prefix, maxWidth);
731    }
732    else if (oid.equals(AccountUsableResponseControl.
733         ACCOUNT_USABLE_RESPONSE_OID))
734    {
735      addAccountUsableResponseControl(lines, c, prefix, maxWidth);
736    }
737    else if (oid.equals(AssuredReplicationResponseControl.
738         ASSURED_REPLICATION_RESPONSE_OID))
739    {
740      addAssuredReplicationResponseControl(lines, c, prefix, maxWidth);
741    }
742    else if (oid.equals(GetAuthorizationEntryResponseControl.
743         GET_AUTHORIZATION_ENTRY_RESPONSE_OID))
744    {
745      addGetAuthorizationEntryResponseControl(lines, c, prefix, maxWidth);
746    }
747    else if (oid.equals(GetBackendSetIDResponseControl.
748         GET_BACKEND_SET_ID_RESPONSE_OID))
749    {
750      addGetBackendSetIDResponseControl(lines, c, prefix, maxWidth);
751    }
752    else if (oid.equals(GetPasswordPolicyStateIssuesResponseControl.
753         GET_PASSWORD_POLICY_STATE_ISSUES_RESPONSE_OID))
754    {
755      addGetPasswordPolicyStateIssuesResponseControl(lines, c, prefix,
756           maxWidth);
757    }
758    else if (oid.equals(GetServerIDResponseControl.GET_SERVER_ID_RESPONSE_OID))
759    {
760      addGetServerIDResponseControl(lines, c, prefix, maxWidth);
761    }
762    else if (oid.equals(GetUserResourceLimitsResponseControl.
763         GET_USER_RESOURCE_LIMITS_RESPONSE_OID))
764    {
765      addGetUserResourceLimitsResponseControl(lines, c, prefix, maxWidth);
766    }
767    else if (oid.equals(IntermediateClientResponseControl.
768         INTERMEDIATE_CLIENT_RESPONSE_OID))
769    {
770      addIntermediateClientResponseControl(lines, c, prefix, maxWidth);
771    }
772    else if (oid.equals(JoinResultControl.JOIN_RESULT_OID))
773    {
774      addJoinResultControl(lines, c, prefix, maxWidth);
775    }
776    else if (oid.equals(MatchingEntryCountResponseControl.
777         MATCHING_ENTRY_COUNT_RESPONSE_OID))
778    {
779      addMatchingEntryCountResponseControl(lines, c, prefix, maxWidth);
780    }
781    else if (oid.equals(PasswordPolicyResponseControl.
782         PASSWORD_POLICY_RESPONSE_OID))
783    {
784      addPasswordPolicyResponseControl(lines, c, prefix, maxWidth);
785    }
786    else if (oid.equals(PasswordValidationDetailsResponseControl.
787         PASSWORD_VALIDATION_DETAILS_RESPONSE_OID))
788    {
789      addPasswordValidationDetailsResponseControl(lines, c, prefix, maxWidth);
790    }
791    else if (oid.equals(SoftDeleteResponseControl.SOFT_DELETE_RESPONSE_OID))
792    {
793      addSoftDeleteResponseControl(lines, c, prefix, maxWidth);
794    }
795    else if (oid.equals(TransactionSettingsResponseControl.
796         TRANSACTION_SETTINGS_RESPONSE_OID))
797    {
798      addTransactionSettingsResponseControl(lines, c, prefix, maxWidth);
799    }
800    else if (oid.equals(UniquenessResponseControl.UNIQUENESS_RESPONSE_OID))
801    {
802      addUniquenessResponseControl(lines, c, prefix, maxWidth);
803    }
804    else
805    {
806      addGenericResponseControl(lines, c, prefix, maxWidth);
807    }
808  }
809
810
811
812  /**
813   * Adds a multi-line string representation of the provided control, which will
814   * be treated as a generic control, to the given list.
815   *
816   * @param  lines     The list to which the lines should be added.
817   * @param  c         The control to be formatted.
818   * @param  prefix    The prefix to use for each line.
819   * @param  maxWidth  The maximum length of each line in characters, including
820   *                   the comment prefix and indent.
821   */
822  private static void addGenericResponseControl(final List<String> lines,
823                                                final Control c,
824                                                final String prefix,
825                                                final int maxWidth)
826  {
827    wrap(lines, INFO_RESULT_UTILS_GENERIC_RESPONSE_CONTROL_HEADER.get(),
828         prefix, maxWidth);
829    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
830         prefix + "     ", maxWidth);
831    wrap(lines,
832         INFO_RESULT_UTILS_RESPONSE_CONTROL_IS_CRITICAL.get(c.isCritical()),
833         prefix + "     ", maxWidth);
834
835    final ASN1OctetString value = c.getValue();
836    if ((value != null) && (value.getValue().length > 0))
837    {
838      wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_RAW_VALUE_HEADER.get(),
839           prefix + "     ", maxWidth);
840
841      // We'll ignore the maximum width for this portion of the output.
842      for (final String line :
843           StaticUtils.stringToLines(
844                StaticUtils.toHexPlusASCII(value.getValue(), 0)))
845      {
846        lines.add(prefix + "          " + line);
847      }
848    }
849  }
850
851
852
853  /**
854   * Adds a multi-line string representation of the provided control, which is
855   * expected to be an authorization identity response control, to the given
856   * list.
857   *
858   * @param  lines     The list to which the lines should be added.
859   * @param  c         The control to be formatted.
860   * @param  prefix    The prefix to use for each line.
861   * @param  maxWidth  The maximum length of each line in characters, including
862   *                   the comment prefix and indent.
863   */
864  private static void addAuthorizationIdentityResponseControl(
865                           final List<String> lines, final Control c,
866                           final String prefix, final int maxWidth)
867  {
868    final AuthorizationIdentityResponseControl decoded;
869    try
870    {
871      decoded = new AuthorizationIdentityResponseControl(c.getOID(),
872           c.isCritical(), c.getValue());
873    }
874    catch (final Exception e)
875    {
876      Debug.debugException(e);
877      addGenericResponseControl(lines, c, prefix, maxWidth);
878      return;
879    }
880
881    wrap(lines, INFO_RESULT_UTILS_AUTHZ_ID_RESPONSE_HEADER.get(), prefix,
882         maxWidth);
883
884    final String indentPrefix = prefix + "     ";
885    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
886         indentPrefix, maxWidth);
887    wrap(lines,
888         INFO_RESULT_UTILS_AUTHZ_ID_RESPONSE_ID.get(
889              decoded.getAuthorizationID()),
890         indentPrefix, maxWidth);
891  }
892
893
894
895  /**
896   * Adds a multi-line string representation of the provided control, which is
897   * expected to be a content sync done control, to the given list.
898   *
899   * @param  lines     The list to which the lines should be added.
900   * @param  c         The control to be formatted.
901   * @param  prefix    The prefix to use for each line.
902   * @param  maxWidth  The maximum length of each line in characters, including
903   *                   the comment prefix and indent.
904   */
905  private static void addContentSyncDoneControl(
906                           final List<String> lines, final Control c,
907                           final String prefix, final int maxWidth)
908  {
909    final ContentSyncDoneControl decoded;
910    try
911    {
912      decoded = new ContentSyncDoneControl(c.getOID(), c.isCritical(),
913           c.getValue());
914    }
915    catch (final Exception e)
916    {
917      Debug.debugException(e);
918      addGenericResponseControl(lines, c, prefix, maxWidth);
919      return;
920    }
921
922    wrap(lines, INFO_RESULT_UTILS_CONTENT_SYNC_DONE_RESPONSE_HEADER.get(),
923         prefix, maxWidth);
924    final String indentPrefix = prefix + "     ";
925    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
926         indentPrefix, maxWidth);
927    wrap(lines,
928         INFO_RESULT_UTILS_CONTENT_SYNC_DONE_REFRESH_DELETES.get(
929              decoded.refreshDeletes()),
930         indentPrefix, maxWidth);
931
932    final ASN1OctetString cookie = decoded.getCookie();
933    if (cookie != null)
934    {
935      wrap(lines, INFO_RESULT_UTILS_CONTENT_SYNC_DONE_COOKIE_HEADER.get(),
936           indentPrefix, maxWidth);
937
938      // We'll ignore the maximum width for this portion of the output.
939      for (final String line :
940           StaticUtils.stringToLines(
941                StaticUtils.toHexPlusASCII(cookie.getValue(), 0)))
942      {
943        lines.add(indentPrefix + "     " + line);
944      }
945    }
946  }
947
948
949
950  /**
951   * Adds a multi-line string representation of the provided control, which is
952   * expected to be a content sync state control, to the given list.
953   *
954   * @param  lines     The list to which the lines should be added.
955   * @param  c         The control to be formatted.
956   * @param  prefix    The prefix to use for each line.
957   * @param  maxWidth  The maximum length of each line in characters, including
958   *                   the comment prefix and indent.
959   */
960  private static void addContentSyncStateControl(
961                           final List<String> lines, final Control c,
962                           final String prefix, final int maxWidth)
963  {
964    final ContentSyncStateControl decoded;
965    try
966    {
967      decoded = new ContentSyncStateControl(c.getOID(), c.isCritical(),
968           c.getValue());
969    }
970    catch (final Exception e)
971    {
972      Debug.debugException(e);
973      addGenericResponseControl(lines, c, prefix, maxWidth);
974      return;
975    }
976
977    wrap(lines, INFO_RESULT_UTILS_CONTENT_SYNC_STATE_RESPONSE_HEADER.get(),
978         prefix, maxWidth);
979    final String indentPrefix = prefix + "     ";
980    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
981         indentPrefix, maxWidth);
982    wrap(lines,
983         INFO_RESULT_UTILS_CONTENT_SYNC_STATE_ENTRY_UUID.get(
984              decoded.getEntryUUID()),
985         indentPrefix, maxWidth);
986    wrap(lines,
987         INFO_RESULT_UTILS_CONTENT_SYNC_STATE_NAME.get(
988              decoded.getState().name()),
989         indentPrefix, maxWidth);
990
991    final ASN1OctetString cookie = decoded.getCookie();
992    if (cookie != null)
993    {
994      wrap(lines, INFO_RESULT_UTILS_CONTENT_SYNC_STATE_COOKIE_HEADER.get(),
995           indentPrefix, maxWidth);
996
997      // We'll ignore the maximum width for this portion of the output.
998      for (final String line :
999           StaticUtils.stringToLines(
1000                StaticUtils.toHexPlusASCII(cookie.getValue(), 0)))
1001      {
1002        lines.add(indentPrefix + "     " + line);
1003      }
1004    }
1005  }
1006
1007
1008
1009  /**
1010   * Adds a multi-line string representation of the provided control, which is
1011   * expected to be an entry change notification control, to the given list.
1012   *
1013   * @param  lines     The list to which the lines should be added.
1014   * @param  c         The control to be formatted.
1015   * @param  prefix    The prefix to use for each line.
1016   * @param  maxWidth  The maximum length of each line in characters, including
1017   *                   the comment prefix and indent.
1018   */
1019  private static void addEntryChangeNotificationControl(
1020                           final List<String> lines, final Control c,
1021                           final String prefix, final int maxWidth)
1022  {
1023    final EntryChangeNotificationControl decoded;
1024    try
1025    {
1026      decoded = new EntryChangeNotificationControl(c.getOID(), c.isCritical(),
1027           c.getValue());
1028    }
1029    catch (final Exception e)
1030    {
1031      Debug.debugException(e);
1032      addGenericResponseControl(lines, c, prefix, maxWidth);
1033      return;
1034    }
1035
1036    wrap(lines, INFO_RESULT_UTILS_ECN_HEADER.get(), prefix, maxWidth);
1037
1038    final String indentPrefix = prefix + "     ";
1039    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
1040         indentPrefix, maxWidth);
1041
1042    final PersistentSearchChangeType changeType = decoded.getChangeType();
1043    if (changeType != null)
1044    {
1045      wrap(lines, INFO_RESULT_UTILS_ECN_CHANGE_TYPE.get(changeType.getName()),
1046           indentPrefix, maxWidth);
1047    }
1048
1049    final long changeNumber = decoded.getChangeNumber();
1050    if (changeNumber >= 0L)
1051    {
1052      wrap(lines, INFO_RESULT_UTILS_ECN_CHANGE_NUMBER.get(changeNumber),
1053           indentPrefix, maxWidth);
1054    }
1055
1056    final String previousDN = decoded.getPreviousDN();
1057    if (previousDN != null)
1058    {
1059      wrap(lines, INFO_RESULT_UTILS_ECN_PREVIOUS_DN.get(previousDN),
1060           indentPrefix, maxWidth);
1061    }
1062  }
1063
1064
1065
1066  /**
1067   * Adds a multi-line string representation of the provided control, which is
1068   * expected to be a password expired control, to the given list.
1069   *
1070   * @param  lines     The list to which the lines should be added.
1071   * @param  c         The control to be formatted.
1072   * @param  prefix    The prefix to use for each line.
1073   * @param  maxWidth  The maximum length of each line in characters, including
1074   *                   the comment prefix and indent.
1075   */
1076  private static void addPasswordExpiredControl(final List<String> lines,
1077                                                final Control c,
1078                                                final String prefix,
1079                                                final int maxWidth)
1080  {
1081    final PasswordExpiredControl decoded;
1082    try
1083    {
1084      decoded = new PasswordExpiredControl(c.getOID(), c.isCritical(),
1085           c.getValue());
1086    }
1087    catch (final Exception e)
1088    {
1089      Debug.debugException(e);
1090      addGenericResponseControl(lines, c, prefix, maxWidth);
1091      return;
1092    }
1093
1094    wrap(lines, INFO_RESULT_UTILS_PASSWORD_EXPIRED_HEADER.get(), prefix,
1095         maxWidth);
1096
1097    final String indentPrefix = prefix + "     ";
1098    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(decoded.getOID()),
1099         indentPrefix, maxWidth);
1100  }
1101
1102
1103
1104  /**
1105   * Adds a multi-line string representation of the provided control, which is
1106   * expected to be a password expiring control, to the given list.
1107   *
1108   * @param  lines     The list to which the lines should be added.
1109   * @param  c         The control to be formatted.
1110   * @param  prefix    The prefix to use for each line.
1111   * @param  maxWidth  The maximum length of each line in characters, including
1112   *                   the comment prefix and indent.
1113   */
1114  private static void addPasswordExpiringControl(final List<String> lines,
1115                                                 final Control c,
1116                                                 final String prefix,
1117                                                 final int maxWidth)
1118  {
1119    final PasswordExpiringControl decoded;
1120    try
1121    {
1122      decoded = new PasswordExpiringControl(c.getOID(), c.isCritical(),
1123           c.getValue());
1124    }
1125    catch (final Exception e)
1126    {
1127      Debug.debugException(e);
1128      addGenericResponseControl(lines, c, prefix, maxWidth);
1129      return;
1130    }
1131
1132    wrap(lines, INFO_RESULT_UTILS_PASSWORD_EXPIRING_HEADER.get(), prefix,
1133         maxWidth);
1134
1135    final String indentPrefix = prefix + "     ";
1136    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
1137         indentPrefix, maxWidth);
1138
1139    final int secondsUntilExpiration = decoded.getSecondsUntilExpiration();
1140    if (secondsUntilExpiration >= 0)
1141    {
1142      wrap(lines,
1143           INFO_RESULT_UTILS_PASSWORD_EXPIRING_SECONDS_UNTIL_EXPIRATION.get(
1144                secondsUntilExpiration),
1145           indentPrefix, maxWidth);
1146    }
1147  }
1148
1149
1150
1151  /**
1152   * Adds a multi-line string representation of the provided control, which is
1153   * expected to be a post-read response control, to the given list.
1154   *
1155   * @param  lines     The list to which the lines should be added.
1156   * @param  c         The control to be formatted.
1157   * @param  prefix    The prefix to use for each line.
1158   * @param  maxWidth  The maximum length of each line in characters, including
1159   *                   the comment prefix and indent.
1160   */
1161  private static void addPostReadResponseControl(
1162                           final List<String> lines, final Control c,
1163                           final String prefix, final int maxWidth)
1164  {
1165    final PostReadResponseControl decoded;
1166    try
1167    {
1168      decoded = new PostReadResponseControl(c.getOID(), c.isCritical(),
1169           c.getValue());
1170    }
1171    catch (final Exception e)
1172    {
1173      Debug.debugException(e);
1174      addGenericResponseControl(lines, c, prefix, maxWidth);
1175      return;
1176    }
1177
1178    wrap(lines, INFO_RESULT_UTILS_POST_READ_HEADER.get(), prefix, maxWidth);
1179
1180    final String indentPrefix = prefix + "     ";
1181    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
1182         indentPrefix, maxWidth);
1183    wrap(lines, INFO_RESULT_UTILS_POST_READ_ENTRY_HEADER.get(c.getOID()),
1184         indentPrefix, maxWidth);
1185    addLDIF(lines, decoded.getEntry(), true, indentPrefix + "     ", maxWidth);
1186  }
1187
1188
1189
1190  /**
1191   * Adds a multi-line string representation of the provided control, which is
1192   * expected to be a pre-read response control, to the given list.
1193   *
1194   * @param  lines     The list to which the lines should be added.
1195   * @param  c         The control to be formatted.
1196   * @param  prefix    The prefix to use for each line.
1197   * @param  maxWidth  The maximum length of each line in characters, including
1198   *                   the comment prefix and indent.
1199   */
1200  private static void addPreReadResponseControl(
1201                           final List<String> lines, final Control c,
1202                           final String prefix, final int maxWidth)
1203  {
1204    final PreReadResponseControl decoded;
1205    try
1206    {
1207      decoded = new PreReadResponseControl(c.getOID(), c.isCritical(),
1208           c.getValue());
1209    }
1210    catch (final Exception e)
1211    {
1212      Debug.debugException(e);
1213      addGenericResponseControl(lines, c, prefix, maxWidth);
1214      return;
1215    }
1216
1217    wrap(lines, INFO_RESULT_UTILS_PRE_READ_HEADER.get(), prefix, maxWidth);
1218
1219    final String indentPrefix = prefix + "     ";
1220    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
1221         indentPrefix, maxWidth);
1222    wrap(lines, INFO_RESULT_UTILS_PRE_READ_ENTRY_HEADER.get(c.getOID()),
1223         indentPrefix, maxWidth);
1224    addLDIF(lines, decoded.getEntry(), true, indentPrefix + "     ", maxWidth);
1225  }
1226
1227
1228
1229  /**
1230   * Adds a multi-line string representation of the provided control, which is
1231   * expected to be a server-side sort response control, to the given list.
1232   *
1233   * @param  lines     The list to which the lines should be added.
1234   * @param  c         The control to be formatted.
1235   * @param  prefix    The prefix to use for each line.
1236   * @param  maxWidth  The maximum length of each line in characters, including
1237   *                   the comment prefix and indent.
1238   */
1239  private static void addServerSideSortResponseControl(
1240                           final List<String> lines, final Control c,
1241                           final String prefix, final int maxWidth)
1242  {
1243    final ServerSideSortResponseControl decoded;
1244    try
1245    {
1246      decoded = new ServerSideSortResponseControl(c.getOID(), c.isCritical(),
1247           c.getValue());
1248    }
1249    catch (final Exception e)
1250    {
1251      Debug.debugException(e);
1252      addGenericResponseControl(lines, c, prefix, maxWidth);
1253      return;
1254    }
1255
1256    wrap(lines, INFO_RESULT_UTILS_SORT_HEADER.get(), prefix, maxWidth);
1257
1258    final String indentPrefix = prefix + "     ";
1259    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
1260         indentPrefix, maxWidth);
1261
1262    final ResultCode resultCode = decoded.getResultCode();
1263    if (resultCode != null)
1264    {
1265      wrap(lines,
1266           INFO_RESULT_UTILS_SORT_RESULT_CODE.get(String.valueOf(resultCode)),
1267           indentPrefix, maxWidth);
1268    }
1269
1270    final String attributeName = decoded.getAttributeName();
1271    if (attributeName != null)
1272    {
1273      wrap(lines, INFO_RESULT_UTILS_SORT_ATTRIBUTE_NAME.get(attributeName),
1274           indentPrefix, maxWidth);
1275    }
1276  }
1277
1278
1279
1280  /**
1281   * Adds a multi-line string representation of the provided control, which is
1282   * expected to be a simple paged results control, to the given list.
1283   *
1284   * @param  lines     The list to which the lines should be added.
1285   * @param  c         The control to be formatted.
1286   * @param  prefix    The prefix to use for each line.
1287   * @param  maxWidth  The maximum length of each line in characters, including
1288   *                   the comment prefix and indent.
1289   */
1290  private static void addSimplePagedResultsControl(
1291                           final List<String> lines, final Control c,
1292                           final String prefix, final int maxWidth)
1293  {
1294    final SimplePagedResultsControl decoded;
1295    try
1296    {
1297      decoded = new SimplePagedResultsControl(c.getOID(), c.isCritical(),
1298           c.getValue());
1299    }
1300    catch (final Exception e)
1301    {
1302      Debug.debugException(e);
1303      addGenericResponseControl(lines, c, prefix, maxWidth);
1304      return;
1305    }
1306
1307    wrap(lines, INFO_RESULT_UTILS_PAGED_RESULTS_HEADER.get(), prefix, maxWidth);
1308
1309    final String indentPrefix = prefix + "     ";
1310    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
1311         indentPrefix, maxWidth);
1312
1313    final int estimatedCount = decoded.getSize();
1314    if (estimatedCount >= 0)
1315    {
1316      wrap(lines, INFO_RESULT_UTILS_PAGED_RESULTS_COUNT.get(estimatedCount),
1317           indentPrefix, maxWidth);
1318    }
1319
1320    final ASN1OctetString cookie = decoded.getCookie();
1321    if (cookie != null)
1322    {
1323      wrap(lines, INFO_RESULT_UTILS_PAGED_RESULTS_COOKIE_HEADER.get(),
1324           indentPrefix, maxWidth);
1325
1326      // We'll ignore the maximum width for this portion of the output.
1327      for (final String line :
1328           StaticUtils.stringToLines(
1329                StaticUtils.toHexPlusASCII(cookie.getValue(), 0)))
1330      {
1331        lines.add(indentPrefix + "     " + line);
1332      }
1333    }
1334  }
1335
1336
1337
1338  /**
1339   * Adds a multi-line string representation of the provided control, which is
1340   * expected to be a virtual list view response control, to the given list.
1341   *
1342   * @param  lines     The list to which the lines should be added.
1343   * @param  c         The control to be formatted.
1344   * @param  prefix    The prefix to use for each line.
1345   * @param  maxWidth  The maximum length of each line in characters, including
1346   *                   the comment prefix and indent.
1347   */
1348  private static void addVirtualListViewResponseControl(
1349                           final List<String> lines, final Control c,
1350                           final String prefix, final int maxWidth)
1351  {
1352    final VirtualListViewResponseControl decoded;
1353    try
1354    {
1355      decoded = new VirtualListViewResponseControl(c.getOID(), c.isCritical(),
1356           c.getValue());
1357    }
1358    catch (final Exception e)
1359    {
1360      Debug.debugException(e);
1361      addGenericResponseControl(lines, c, prefix, maxWidth);
1362      return;
1363    }
1364
1365    wrap(lines, INFO_RESULT_UTILS_VLV_HEADER.get(), prefix, maxWidth);
1366
1367    final String indentPrefix = prefix + "     ";
1368    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
1369         indentPrefix, maxWidth);
1370
1371    final ResultCode resultCode = decoded.getResultCode();
1372    if (resultCode != null)
1373    {
1374      wrap(lines,
1375           INFO_RESULT_UTILS_VLV_RESULT_CODE.get(String.valueOf(resultCode)),
1376           indentPrefix, maxWidth);
1377    }
1378
1379    final int contentCount = decoded.getContentCount();
1380    if (contentCount >= 0)
1381    {
1382      wrap(lines, INFO_RESULT_UTILS_VLV_CONTENT_COUNT.get(contentCount),
1383           indentPrefix, maxWidth);
1384    }
1385
1386    final int targetPosition = decoded.getTargetPosition();
1387    if (targetPosition >= 0)
1388    {
1389      wrap(lines, INFO_RESULT_UTILS_VLV_TARGET_POSITION.get(targetPosition),
1390           indentPrefix, maxWidth);
1391    }
1392
1393    final ASN1OctetString contextID = decoded.getContextID();
1394    if (contextID != null)
1395    {
1396      wrap(lines, INFO_RESULT_UTILS_VLV_CONTEXT_ID_HEADER.get(),
1397           indentPrefix, maxWidth);
1398
1399      // We'll ignore the maximum width for this portion of the output.
1400      for (final String line :
1401           StaticUtils.stringToLines(
1402                StaticUtils.toHexPlusASCII(contextID.getValue(), 0)))
1403      {
1404        lines.add(indentPrefix + "     " + line);
1405      }
1406    }
1407  }
1408
1409
1410
1411  /**
1412   * Adds a multi-line string representation of the provided control, which is
1413   * expected to be an account usable response control, to the given list.
1414   *
1415   * @param  lines     The list to which the lines should be added.
1416   * @param  c         The control to be formatted.
1417   * @param  prefix    The prefix to use for each line.
1418   * @param  maxWidth  The maximum length of each line in characters, including
1419   *                   the comment prefix and indent.
1420   */
1421  private static void addAccountUsableResponseControl(
1422                           final List<String> lines, final Control c,
1423                           final String prefix, final int maxWidth)
1424  {
1425    final AccountUsableResponseControl decoded;
1426    try
1427    {
1428      decoded = new AccountUsableResponseControl(c.getOID(), c.isCritical(),
1429           c.getValue());
1430    }
1431    catch (final Exception e)
1432    {
1433      Debug.debugException(e);
1434      addGenericResponseControl(lines, c, prefix, maxWidth);
1435      return;
1436    }
1437
1438    wrap(lines, INFO_RESULT_UTILS_ACCOUNT_USABLE_HEADER.get(), prefix,
1439         maxWidth);
1440
1441    final String indentPrefix = prefix + "     ";
1442    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
1443         indentPrefix, maxWidth);
1444    wrap(lines,
1445         INFO_RESULT_UTILS_ACCOUNT_USABLE_IS_USABLE.get(decoded.isUsable()),
1446         indentPrefix, maxWidth);
1447
1448    final List<String> unusableReasons = decoded.getUnusableReasons();
1449    if ((unusableReasons != null) && (! unusableReasons.isEmpty()))
1450    {
1451      wrap(lines,
1452           INFO_RESULT_UTILS_ACCOUNT_USABLE_UNUSABLE_REASONS_HEADER.get(),
1453           indentPrefix, maxWidth);
1454      for (final String reason : unusableReasons)
1455      {
1456        wrap(lines, reason, indentPrefix + "     ", maxWidth);
1457      }
1458    }
1459
1460    wrap(lines,
1461         INFO_RESULT_UTILS_ACCOUNT_USABLE_PW_EXPIRED.get(
1462              decoded.passwordIsExpired()),
1463         indentPrefix, maxWidth);
1464    wrap(lines,
1465         INFO_RESULT_UTILS_ACCOUNT_USABLE_MUST_CHANGE_PW.get(
1466              decoded.mustChangePassword()),
1467         indentPrefix, maxWidth);
1468    wrap(lines,
1469         INFO_RESULT_UTILS_ACCOUNT_USABLE_IS_INACTIVE.get(decoded.isInactive()),
1470         indentPrefix, maxWidth);
1471
1472    final int remainingGraceLogins = decoded.getRemainingGraceLogins();
1473    if (remainingGraceLogins >= 0)
1474    {
1475      wrap(lines,
1476           INFO_RESULT_UTILS_ACCOUNT_USABLE_REMAINING_GRACE.get(
1477                remainingGraceLogins),
1478           indentPrefix, maxWidth);
1479    }
1480
1481    final int secondsUntilExpiration = decoded.getSecondsUntilExpiration();
1482    if (secondsUntilExpiration >= 0)
1483    {
1484      wrap(lines,
1485           INFO_RESULT_UTILS_ACCOUNT_USABLE_SECONDS_UNTIL_EXPIRATION.get(
1486                secondsUntilExpiration),
1487           indentPrefix, maxWidth);
1488    }
1489
1490    final int secondsUntilUnlock = decoded.getSecondsUntilUnlock();
1491    if (secondsUntilUnlock >= 0)
1492    {
1493      wrap(lines,
1494           INFO_RESULT_UTILS_ACCOUNT_USABLE_SECONDS_UNTIL_UNLOCK.get(
1495                secondsUntilUnlock),
1496           indentPrefix, maxWidth);
1497    }
1498  }
1499
1500
1501
1502  /**
1503   * Adds a multi-line string representation of the provided control, which is
1504   * expected to be an assured replication response control, to the given list.
1505   *
1506   * @param  lines     The list to which the lines should be added.
1507   * @param  c         The control to be formatted.
1508   * @param  prefix    The prefix to use for each line.
1509   * @param  maxWidth  The maximum length of each line in characters, including
1510   *                   the comment prefix and indent.
1511   */
1512  private static void addAssuredReplicationResponseControl(
1513                           final List<String> lines, final Control c,
1514                           final String prefix, final int maxWidth)
1515  {
1516    final AssuredReplicationResponseControl decoded;
1517    try
1518    {
1519      decoded = new AssuredReplicationResponseControl(c.getOID(),
1520           c.isCritical(), c.getValue());
1521    }
1522    catch (final Exception e)
1523    {
1524      Debug.debugException(e);
1525      addGenericResponseControl(lines, c, prefix, maxWidth);
1526      return;
1527    }
1528
1529    wrap(lines, INFO_RESULT_UTILS_ASSURED_REPL_HEADER.get(), prefix, maxWidth);
1530
1531    final String indentPrefix = prefix + "     ";
1532    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
1533         indentPrefix, maxWidth);
1534
1535    final String csn = decoded.getCSN();
1536    if (csn != null)
1537    {
1538      wrap(lines, INFO_RESULT_UTILS_ASSURED_REPL_CSN.get(csn), indentPrefix,
1539           maxWidth);
1540    }
1541
1542    final AssuredReplicationLocalLevel localLevel = decoded.getLocalLevel();
1543    if (localLevel != null)
1544    {
1545      wrap(lines,
1546           INFO_RESULT_UTILS_ASSURED_REPL_LOCAL_LEVEL.get(localLevel.name()),
1547           indentPrefix, maxWidth);
1548    }
1549
1550    wrap(lines,
1551         INFO_RESULT_UTILS_ASSURED_REPL_LOCAL_SATISFIED.get(
1552              decoded.localAssuranceSatisfied()),
1553         indentPrefix, maxWidth);
1554
1555    final String localMessage = decoded.getLocalAssuranceMessage();
1556    if (localMessage != null)
1557    {
1558      wrap(lines,
1559           INFO_RESULT_UTILS_ASSURED_REPL_LOCAL_MESSAGE.get(localMessage),
1560           indentPrefix, maxWidth);
1561    }
1562
1563    final AssuredReplicationRemoteLevel remoteLevel = decoded.getRemoteLevel();
1564    if (remoteLevel != null)
1565    {
1566      wrap(lines,
1567           INFO_RESULT_UTILS_ASSURED_REPL_REMOTE_LEVEL.get(remoteLevel.name()),
1568           indentPrefix, maxWidth);
1569    }
1570
1571    wrap(lines,
1572         INFO_RESULT_UTILS_ASSURED_REPL_REMOTE_SATISFIED.get(
1573              decoded.remoteAssuranceSatisfied()),
1574         indentPrefix, maxWidth);
1575
1576    final String remoteMessage = decoded.getRemoteAssuranceMessage();
1577    if (remoteMessage != null)
1578    {
1579      wrap(lines,
1580           INFO_RESULT_UTILS_ASSURED_REPL_REMOTE_MESSAGE.get(remoteMessage),
1581           indentPrefix, maxWidth);
1582    }
1583
1584    final List<AssuredReplicationServerResult> serverResults =
1585         decoded.getServerResults();
1586    if (serverResults != null)
1587    {
1588      for (final AssuredReplicationServerResult r : serverResults)
1589      {
1590        wrap(lines,
1591             INFO_RESULT_UTILS_ASSURED_REPL_SERVER_RESULT_HEADER.get(),
1592             indentPrefix, maxWidth);
1593
1594        final AssuredReplicationServerResultCode rc = r.getResultCode();
1595        if (rc != null)
1596        {
1597          wrap(lines,
1598               INFO_RESULT_UTILS_ASSURED_REPL_SERVER_RESULT_CODE.get(rc.name()),
1599               indentPrefix + "     ", maxWidth);
1600        }
1601
1602        final Short replicationServerID = r.getReplicationServerID();
1603        if (replicationServerID != null)
1604        {
1605          wrap(lines,
1606               INFO_RESULT_UTILS_ASSURED_REPL_SERVER_RESULT_REPL_SERVER_ID.get(
1607                    replicationServerID),
1608               indentPrefix + "     ", maxWidth);
1609        }
1610
1611        final Short replicaID = r.getReplicaID();
1612        if (replicaID != null)
1613        {
1614          wrap(lines,
1615               INFO_RESULT_UTILS_ASSURED_REPL_SERVER_RESULT_REPL_ID.get(
1616                    replicaID),
1617               indentPrefix + "     ", maxWidth);
1618        }
1619      }
1620    }
1621  }
1622
1623
1624
1625  /**
1626   * Adds a multi-line string representation of the provided control, which is
1627   * expected to be a get authorization entry response control, to the given
1628   * list.
1629   *
1630   * @param  lines     The list to which the lines should be added.
1631   * @param  c         The control to be formatted.
1632   * @param  prefix    The prefix to use for each line.
1633   * @param  maxWidth  The maximum length of each line in characters, including
1634   *                   the comment prefix and indent.
1635   */
1636  private static void addGetAuthorizationEntryResponseControl(
1637                           final List<String> lines, final Control c,
1638                           final String prefix, final int maxWidth)
1639  {
1640    final GetAuthorizationEntryResponseControl decoded;
1641    try
1642    {
1643      decoded = new GetAuthorizationEntryResponseControl(c.getOID(),
1644           c.isCritical(), c.getValue());
1645    }
1646    catch (final Exception e)
1647    {
1648      Debug.debugException(e);
1649      addGenericResponseControl(lines, c, prefix, maxWidth);
1650      return;
1651    }
1652
1653    wrap(lines, INFO_RESULT_UTILS_GET_AUTHZ_ENTRY_HEADER.get(), prefix,
1654         maxWidth);
1655
1656    final String indentPrefix = prefix + "     ";
1657    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
1658         indentPrefix, maxWidth);
1659    wrap(lines,
1660         INFO_RESULT_UTILS_GET_AUTHZ_ENTRY_IS_AUTHENTICATED.get(
1661              decoded.isAuthenticated()),
1662         indentPrefix, maxWidth);
1663
1664    if (! decoded.isAuthenticated())
1665    {
1666      return;
1667    }
1668
1669    wrap(lines,
1670         INFO_RESULT_UTILS_GET_AUTHZ_ENTRY_IDS_MATCH.get(
1671              decoded.identitiesMatch()),
1672         indentPrefix, maxWidth);
1673
1674    final String authNID = decoded.getAuthNID();
1675    if (authNID != null)
1676    {
1677      wrap(lines, INFO_RESULT_UTILS_GET_AUTHZ_ENTRY_AUTHN_ID.get(authNID),
1678           indentPrefix, maxWidth);
1679    }
1680
1681    final Entry authNEntry = decoded.getAuthNEntry();
1682    if (authNEntry != null)
1683    {
1684      wrap(lines, INFO_RESULT_UTILS_GET_AUTHZ_ENTRY_AUTHN_ENTRY_HEADER.get(),
1685           indentPrefix, maxWidth);
1686      addLDIF(lines, authNEntry, true, indentPrefix + "     ", maxWidth);
1687    }
1688
1689    if (decoded.identitiesMatch())
1690    {
1691      return;
1692    }
1693
1694    final String authZID = decoded.getAuthZID();
1695    if (authZID != null)
1696    {
1697      wrap(lines, INFO_RESULT_UTILS_GET_AUTHZ_ENTRY_AUTHZ_ID.get(authZID),
1698           indentPrefix, maxWidth);
1699    }
1700
1701    final Entry authZEntry = decoded.getAuthZEntry();
1702    if (authZEntry != null)
1703    {
1704      wrap(lines, INFO_RESULT_UTILS_GET_AUTHZ_ENTRY_AUTHZ_ENTRY_HEADER.get(),
1705           indentPrefix, maxWidth);
1706      addLDIF(lines, authZEntry, true, indentPrefix + "     ", maxWidth);
1707    }
1708  }
1709
1710
1711
1712  /**
1713   * Adds a multi-line string representation of the provided control, which is
1714   * expected to be a get backend set ID response control, to the given list.
1715   *
1716   * @param  lines     The list to which the lines should be added.
1717   * @param  c         The control to be formatted.
1718   * @param  prefix    The prefix to use for each line.
1719   * @param  maxWidth  The maximum length of each line in characters, including
1720   *                   the comment prefix and indent.
1721   */
1722  private static void addGetBackendSetIDResponseControl(
1723                           final List<String> lines, final Control c,
1724                           final String prefix, final int maxWidth)
1725  {
1726    final GetBackendSetIDResponseControl decoded;
1727    try
1728    {
1729      decoded = new GetBackendSetIDResponseControl(c.getOID(), c.isCritical(),
1730           c.getValue());
1731    }
1732    catch (final Exception e)
1733    {
1734      Debug.debugException(e);
1735      addGenericResponseControl(lines, c, prefix, maxWidth);
1736      return;
1737    }
1738
1739    wrap(lines, INFO_RESULT_UTILS_GET_BACKEND_SET_ID_HEADER.get(), prefix,
1740         maxWidth);
1741
1742    final String indentPrefix = prefix + "     ";
1743    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
1744         indentPrefix, maxWidth);
1745    wrap(lines,
1746         INFO_RESULT_UTILS_GET_BACKEND_SET_ID_EB_RP_ID.get(
1747              decoded.getEntryBalancingRequestProcessorID()),
1748         indentPrefix, maxWidth);
1749
1750    for (final String id : decoded.getBackendSetIDs())
1751    {
1752      wrap(lines, INFO_RESULT_UTILS_GET_BACKEND_SET_ID.get(id), indentPrefix,
1753           maxWidth);
1754    }
1755  }
1756
1757
1758
1759  /**
1760   * Adds a multi-line string representation of the provided control, which is
1761   * expected to be a get password policy state issues response control, to the
1762   * given list.
1763   *
1764   * @param  lines     The list to which the lines should be added.
1765   * @param  c         The control to be formatted.
1766   * @param  prefix    The prefix to use for each line.
1767   * @param  maxWidth  The maximum length of each line in characters, including
1768   *                   the comment prefix and indent.
1769   */
1770  private static void addGetPasswordPolicyStateIssuesResponseControl(
1771                           final List<String> lines, final Control c,
1772                           final String prefix, final int maxWidth)
1773  {
1774    final GetPasswordPolicyStateIssuesResponseControl decoded;
1775    try
1776    {
1777      decoded = new GetPasswordPolicyStateIssuesResponseControl(c.getOID(),
1778           c.isCritical(), c.getValue());
1779    }
1780    catch (final Exception e)
1781    {
1782      Debug.debugException(e);
1783      addGenericResponseControl(lines, c, prefix, maxWidth);
1784      return;
1785    }
1786
1787    wrap(lines, INFO_RESULT_UTILS_GET_PW_STATE_ISSUES_HEADER.get(), prefix,
1788         maxWidth);
1789
1790    final String indentPrefix = prefix + "     ";
1791    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
1792         indentPrefix, maxWidth);
1793
1794    final String doubleIndentPrefix = indentPrefix + "     ";
1795    final AuthenticationFailureReason authFailureReason =
1796         decoded.getAuthenticationFailureReason();
1797    if (authFailureReason != null)
1798    {
1799      wrap(lines,
1800           INFO_RESULT_UTILS_GET_PW_STATE_ISSUES_FAILURE_REASON_HEADER.get(),
1801           indentPrefix, maxWidth);
1802      wrap(lines,
1803           INFO_RESULT_UTILS_GET_PW_STATE_ISSUES_FAILURE_TYPE.get(
1804                authFailureReason.getName()),
1805           doubleIndentPrefix, maxWidth);
1806
1807      final String message = authFailureReason.getMessage();
1808      if (message != null)
1809      {
1810        wrap(lines,
1811             INFO_RESULT_UTILS_GET_PW_STATE_ISSUES_FAILURE_MESSAGE.get(message),
1812             doubleIndentPrefix, maxWidth);
1813      }
1814    }
1815
1816    final List<PasswordPolicyStateAccountUsabilityError> errors =
1817         decoded.getErrors();
1818    if (errors != null)
1819    {
1820      for (final PasswordPolicyStateAccountUsabilityError e : errors)
1821      {
1822        wrap(lines, INFO_RESULT_UTILS_GET_PW_STATE_ISSUES_ERROR_HEADER.get(),
1823             indentPrefix, maxWidth);
1824        wrap(lines,
1825             INFO_RESULT_UTILS_GET_PW_STATE_ISSUES_ERROR_NAME.get(e.getName()),
1826             doubleIndentPrefix, maxWidth);
1827
1828        final String message = e.getMessage();
1829        if (message != null)
1830        {
1831          wrap(lines,
1832               INFO_RESULT_UTILS_GET_PW_STATE_ISSUES_ERROR_MESSAGE.get(message),
1833               doubleIndentPrefix, maxWidth);
1834        }
1835      }
1836    }
1837
1838    final List<PasswordPolicyStateAccountUsabilityWarning> warnings =
1839         decoded.getWarnings();
1840    if (warnings != null)
1841    {
1842      for (final PasswordPolicyStateAccountUsabilityWarning w : warnings)
1843      {
1844        wrap(lines, INFO_RESULT_UTILS_GET_PW_STATE_ISSUES_WARNING_HEADER.get(),
1845             indentPrefix, maxWidth);
1846        wrap(lines,
1847             INFO_RESULT_UTILS_GET_PW_STATE_ISSUES_WARNING_NAME.get(
1848                  w.getName()),
1849             doubleIndentPrefix, maxWidth);
1850
1851        final String message = w.getMessage();
1852        if (message != null)
1853        {
1854          wrap(lines,
1855               INFO_RESULT_UTILS_GET_PW_STATE_ISSUES_WARNING_MESSAGE.get(
1856                    message),
1857               doubleIndentPrefix, maxWidth);
1858        }
1859      }
1860    }
1861
1862    final List<PasswordPolicyStateAccountUsabilityNotice> notices =
1863         decoded.getNotices();
1864    if (notices != null)
1865    {
1866      for (final PasswordPolicyStateAccountUsabilityNotice n : notices)
1867      {
1868        wrap(lines, INFO_RESULT_UTILS_GET_PW_STATE_ISSUES_NOTICE_HEADER.get(),
1869             indentPrefix, maxWidth);
1870        wrap(lines,
1871             INFO_RESULT_UTILS_GET_PW_STATE_ISSUES_NOTICE_NAME.get(n.getName()),
1872             doubleIndentPrefix, maxWidth);
1873
1874        final String message = n.getMessage();
1875        if (message != null)
1876        {
1877          wrap(lines,
1878               INFO_RESULT_UTILS_GET_PW_STATE_ISSUES_NOTICE_MESSAGE.get(
1879                    message),
1880               doubleIndentPrefix, maxWidth);
1881        }
1882      }
1883    }
1884  }
1885
1886
1887
1888  /**
1889   * Adds a multi-line string representation of the provided control, which is
1890   * expected to be a get server ID response control, to the given list.
1891   *
1892   * @param  lines     The list to which the lines should be added.
1893   * @param  c         The control to be formatted.
1894   * @param  prefix    The prefix to use for each line.
1895   * @param  maxWidth  The maximum length of each line in characters, including
1896   *                   the comment prefix and indent.
1897   */
1898  private static void addGetServerIDResponseControl(
1899                           final List<String> lines, final Control c,
1900                           final String prefix, final int maxWidth)
1901  {
1902    final GetServerIDResponseControl decoded;
1903    try
1904    {
1905      decoded = new GetServerIDResponseControl(c.getOID(), c.isCritical(),
1906           c.getValue());
1907    }
1908    catch (final Exception e)
1909    {
1910      Debug.debugException(e);
1911      addGenericResponseControl(lines, c, prefix, maxWidth);
1912      return;
1913    }
1914
1915
1916    wrap(lines, INFO_RESULT_UTILS_GET_SERVER_ID_HEADER.get(), prefix,
1917         maxWidth);
1918
1919    final String indentPrefix = prefix + "     ";
1920    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
1921         indentPrefix, maxWidth);
1922    wrap(lines, INFO_RESULT_UTILS_GET_SERVER_ID.get(decoded.getServerID()),
1923         indentPrefix, maxWidth);
1924  }
1925
1926
1927
1928  /**
1929   * Adds a multi-line string representation of the provided control, which is
1930   * expected to be a get user resource limits response control, to the given
1931   * list.
1932   *
1933   * @param  lines     The list to which the lines should be added.
1934   * @param  c         The control to be formatted.
1935   * @param  prefix    The prefix to use for each line.
1936   * @param  maxWidth  The maximum length of each line in characters, including
1937   *                   the comment prefix and indent.
1938   */
1939  private static void addGetUserResourceLimitsResponseControl(
1940                           final List<String> lines, final Control c,
1941                           final String prefix, final int maxWidth)
1942  {
1943    final GetUserResourceLimitsResponseControl decoded;
1944    try
1945    {
1946      decoded = new GetUserResourceLimitsResponseControl(c.getOID(),
1947           c.isCritical(), c.getValue());
1948    }
1949    catch (final Exception e)
1950    {
1951      Debug.debugException(e);
1952      addGenericResponseControl(lines, c, prefix, maxWidth);
1953      return;
1954    }
1955
1956    wrap(lines, INFO_RESULT_UTILS_GET_USER_RLIM_HEADER.get(), prefix,
1957         maxWidth);
1958
1959    final String indentPrefix = prefix + "     ";
1960    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
1961         indentPrefix, maxWidth);
1962
1963    final Long sizeLimit = decoded.getSizeLimit();
1964    if (sizeLimit != null)
1965    {
1966      final String value;
1967      if (sizeLimit > 0L)
1968      {
1969        value = String.valueOf(sizeLimit);
1970      }
1971      else
1972      {
1973        value = INFO_RESULT_UTILS_GET_USER_RLIM_VALUE_UNLIMITED.get();
1974      }
1975
1976      wrap(lines, INFO_RESULT_UTILS_GET_USER_RLIM_SIZE_LIMIT.get(value),
1977           indentPrefix, maxWidth);
1978    }
1979
1980    final Long timeLimit = decoded.getTimeLimitSeconds();
1981    if (timeLimit != null)
1982    {
1983      final String value;
1984      if (timeLimit > 0L)
1985      {
1986        value = timeLimit + " " +
1987             INFO_RESULT_UTILS_GET_USER_RLIM_UNIT_SECONDS.get();
1988      }
1989      else
1990      {
1991        value = INFO_RESULT_UTILS_GET_USER_RLIM_VALUE_UNLIMITED.get();
1992      }
1993
1994      wrap(lines, INFO_RESULT_UTILS_GET_USER_RLIM_TIME_LIMIT.get(value),
1995           indentPrefix, maxWidth);
1996    }
1997
1998    final Long idleTimeLimit = decoded.getIdleTimeLimitSeconds();
1999    if (idleTimeLimit != null)
2000    {
2001      final String value;
2002      if (idleTimeLimit > 0L)
2003      {
2004        value = idleTimeLimit + " " +
2005             INFO_RESULT_UTILS_GET_USER_RLIM_UNIT_SECONDS.get();
2006      }
2007      else
2008      {
2009        value = INFO_RESULT_UTILS_GET_USER_RLIM_VALUE_UNLIMITED.get();
2010      }
2011
2012      wrap(lines, INFO_RESULT_UTILS_GET_USER_RLIM_IDLE_TIME_LIMIT.get(value),
2013           indentPrefix, maxWidth);
2014    }
2015
2016    final Long lookthroughLimit = decoded.getLookthroughLimit();
2017    if (lookthroughLimit != null)
2018    {
2019      final String value;
2020      if (lookthroughLimit > 0L)
2021      {
2022        value = String.valueOf(lookthroughLimit);
2023      }
2024      else
2025      {
2026        value = INFO_RESULT_UTILS_GET_USER_RLIM_VALUE_UNLIMITED.get();
2027      }
2028
2029      wrap(lines, INFO_RESULT_UTILS_GET_USER_RLIM_LOOKTHROUGH_LIMIT.get(value),
2030           indentPrefix, maxWidth);
2031    }
2032
2033    final String equivalentUserDN = decoded.getEquivalentAuthzUserDN();
2034    if (equivalentUserDN != null)
2035    {
2036      wrap(lines,
2037           INFO_RESULT_UTILS_GET_USER_RLIM_EQUIVALENT_AUTHZ_USER_DN.get(
2038                equivalentUserDN),
2039           indentPrefix, maxWidth);
2040    }
2041
2042    final String ccpName = decoded.getClientConnectionPolicyName();
2043    if (ccpName != null)
2044    {
2045      wrap(lines, INFO_RESULT_UTILS_GET_USER_RLIM_CCP_NAME.get(ccpName),
2046           indentPrefix, maxWidth);
2047    }
2048
2049    final String doubleIndentPrefix = indentPrefix + "     ";
2050    final List<String> groupDNs = decoded.getGroupDNs();
2051    if ((groupDNs != null) && (! groupDNs.isEmpty()))
2052    {
2053      wrap(lines, INFO_RESULT_UTILS_GET_USER_RLIM_GROUP_DNS_HEADER.get(),
2054           indentPrefix, maxWidth);
2055      for (final String groupDN : groupDNs)
2056      {
2057        wrap(lines, groupDN, doubleIndentPrefix, maxWidth);
2058      }
2059    }
2060
2061    final List<String> privilegeNames = decoded.getPrivilegeNames();
2062    if ((privilegeNames != null) && (! privilegeNames.isEmpty()))
2063    {
2064      wrap(lines, INFO_RESULT_UTILS_GET_USER_RLIM_PRIVILEGES_HEADER.get(),
2065           indentPrefix, maxWidth);
2066      for (final String privilegeName : privilegeNames)
2067      {
2068        wrap(lines, privilegeName, doubleIndentPrefix, maxWidth);
2069      }
2070    }
2071
2072    final List<Attribute> otherAttrs = decoded.getOtherAttributes();
2073    if ((otherAttrs != null) && (! otherAttrs.isEmpty()))
2074    {
2075      wrap(lines, INFO_RESULT_UTILS_GET_USER_RLIM_OTHER_ATTRIBUTES_HEADER.get(),
2076           indentPrefix, maxWidth);
2077      addLDIF(lines, new Entry("", otherAttrs), false, doubleIndentPrefix,
2078           maxWidth);
2079    }
2080  }
2081
2082
2083
2084  /**
2085   * Adds a multi-line string representation of the provided control, which is
2086   * expected to be an intermediate client response control, to the given list.
2087   *
2088   * @param  lines     The list to which the lines should be added.
2089   * @param  c         The control to be formatted.
2090   * @param  prefix    The prefix to use for each line.
2091   * @param  maxWidth  The maximum length of each line in characters, including
2092   *                   the comment prefix and indent.
2093   */
2094  private static void addIntermediateClientResponseControl(
2095                           final List<String> lines, final Control c,
2096                           final String prefix, final int maxWidth)
2097  {
2098    final IntermediateClientResponseControl decoded;
2099    try
2100    {
2101      decoded = new IntermediateClientResponseControl(c.getOID(),
2102           c.isCritical(), c.getValue());
2103    }
2104    catch (final Exception e)
2105    {
2106      Debug.debugException(e);
2107      addGenericResponseControl(lines, c, prefix, maxWidth);
2108      return;
2109    }
2110
2111    wrap(lines, INFO_RESULT_UTILS_INTERMEDIATE_CLIENT_HEADER.get(), prefix,
2112         maxWidth);
2113
2114    final String indentPrefix = prefix + "     ";
2115    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
2116         indentPrefix, maxWidth);
2117    addIntermediateResponseValue(lines, decoded.getResponseValue(),
2118         indentPrefix, maxWidth);
2119  }
2120
2121
2122
2123  /**
2124   * Adds a multi-line string representation of the provided intermediate
2125   * response value to the given list.
2126   *
2127   * @param  lines     The list to which the lines should be added.
2128   * @param  v         The value to be formatted.
2129   * @param  prefix    The prefix to use for each line.
2130   * @param  maxWidth  The maximum length of each line in characters, including
2131   *                   the comment prefix and indent.
2132   */
2133  private static void addIntermediateResponseValue(final List<String> lines,
2134                           final IntermediateClientResponseValue v,
2135                           final String prefix, final int maxWidth)
2136  {
2137    final String address = v.getUpstreamServerAddress();
2138    if (address != null)
2139    {
2140      wrap(lines,
2141           INFO_RESULT_UTILS_INTERMEDIATE_CLIENT_UPSTREAM_ADDRESS.get(address),
2142           prefix, maxWidth);
2143    }
2144
2145    final Boolean secure = v.upstreamServerSecure();
2146    if (secure != null)
2147    {
2148      wrap(lines,
2149           INFO_RESULT_UTILS_INTERMEDIATE_CLIENT_UPSTREAM_SECURE.get(
2150                String.valueOf(secure)),
2151           prefix, maxWidth);
2152    }
2153
2154    final String serverName = v.getServerName();
2155    if (serverName != null)
2156    {
2157      wrap(lines,
2158           INFO_RESULT_UTILS_INTERMEDIATE_CLIENT_SERVER_NAME.get(serverName),
2159           prefix, maxWidth);
2160    }
2161
2162    final String sessionID = v.getServerSessionID();
2163    if (sessionID != null)
2164    {
2165      wrap(lines,
2166           INFO_RESULT_UTILS_INTERMEDIATE_CLIENT_SESSION_ID.get(sessionID),
2167           prefix, maxWidth);
2168    }
2169
2170    final String responseID = v.getServerResponseID();
2171    if (responseID != null)
2172    {
2173      wrap(lines,
2174           INFO_RESULT_UTILS_INTERMEDIATE_CLIENT_RESPONSE_ID.get(responseID),
2175           prefix, maxWidth);
2176    }
2177
2178    final IntermediateClientResponseValue upstreamResponse =
2179         v.getUpstreamResponse();
2180    if (upstreamResponse != null)
2181    {
2182      wrap(lines,
2183           INFO_RESULT_UTILS_INTERMEDIATE_CLIENT_UPSTREAM_RESPONSE_HEADER.get(),
2184           prefix, maxWidth);
2185      addIntermediateResponseValue(lines, upstreamResponse, prefix + "     ",
2186           maxWidth);
2187    }
2188  }
2189
2190
2191
2192  /**
2193   * Adds a multi-line string representation of the provided control, which is
2194   * expected to be a join result control, to the given list.
2195   *
2196   * @param  lines     The list to which the lines should be added.
2197   * @param  c         The control to be formatted.
2198   * @param  prefix    The prefix to use for each line.
2199   * @param  maxWidth  The maximum length of each line in characters, including
2200   *                   the comment prefix and indent.
2201   */
2202  private static void addJoinResultControl(
2203                           final List<String> lines, final Control c,
2204                           final String prefix, final int maxWidth)
2205  {
2206    final JoinResultControl decoded;
2207    try
2208    {
2209      decoded = new JoinResultControl(c.getOID(), c.isCritical(), c.getValue());
2210    }
2211    catch (final Exception e)
2212    {
2213      Debug.debugException(e);
2214      addGenericResponseControl(lines, c, prefix, maxWidth);
2215      return;
2216    }
2217
2218    wrap(lines, INFO_RESULT_UTILS_JOIN_HEADER.get(), prefix,
2219         maxWidth);
2220
2221    final String indentPrefix = prefix + "     ";
2222    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
2223         indentPrefix, maxWidth);
2224
2225    final ResultCode resultCode = decoded.getResultCode();
2226    if (resultCode != null)
2227    {
2228      wrap(lines,
2229           INFO_RESULT_UTILS_JOIN_RESULT_CODE.get(
2230                String.valueOf(resultCode)),
2231           indentPrefix, maxWidth);
2232    }
2233
2234    final String diagnosticMessage = decoded.getDiagnosticMessage();
2235    if (diagnosticMessage != null)
2236    {
2237      wrap(lines,
2238           INFO_RESULT_UTILS_JOIN_DIAGNOSTIC_MESSAGE.get(diagnosticMessage),
2239           indentPrefix, maxWidth);
2240    }
2241
2242    final String matchedDN = decoded.getMatchedDN();
2243    if (matchedDN != null)
2244    {
2245      wrap(lines, INFO_RESULT_UTILS_JOIN_MATCHED_DN.get(matchedDN),
2246           indentPrefix, maxWidth);
2247    }
2248
2249    final List<String> referralURLs = decoded.getReferralURLs();
2250    if (referralURLs != null)
2251    {
2252      for (final String referralURL : referralURLs)
2253      {
2254        wrap(lines, INFO_RESULT_UTILS_JOIN_REFERRAL_URL.get(referralURL),
2255             indentPrefix, maxWidth);
2256      }
2257    }
2258
2259    final List<JoinedEntry> joinedEntries = decoded.getJoinResults();
2260    if (joinedEntries != null)
2261    {
2262      for (final JoinedEntry e : joinedEntries)
2263      {
2264        addJoinedEntry(lines, e, indentPrefix, maxWidth);
2265      }
2266    }
2267  }
2268
2269
2270
2271  /**
2272   * Adds a multi-line string representation of the provided joined entry to the
2273   * given list.
2274   *
2275   * @param  lines        The list to which the lines should be added.
2276   * @param  joinedEntry  The joined entry to be formatted.
2277   * @param  prefix       The prefix to use for each line.
2278   * @param  maxWidth     The maximum length of each line in characters,
2279   *                      including the comment prefix and indent.
2280   */
2281  private static void addJoinedEntry(final List<String> lines,
2282                                     final JoinedEntry joinedEntry,
2283                                     final String prefix, final int maxWidth)
2284  {
2285    wrap(lines, INFO_RESULT_UTILS_JOINED_WITH_ENTRY_HEADER.get(), prefix,
2286         maxWidth);
2287    addLDIF(lines, joinedEntry, true, prefix + "     ", maxWidth);
2288
2289    final List<JoinedEntry> nestedJoinResults =
2290         joinedEntry.getNestedJoinResults();
2291    if (nestedJoinResults != null)
2292    {
2293      for (final JoinedEntry e : nestedJoinResults)
2294      {
2295        addJoinedEntry(lines, e, prefix + "          ", maxWidth);
2296      }
2297    }
2298  }
2299
2300
2301
2302  /**
2303   * Adds a multi-line string representation of the provided control, which is
2304   * expected to be a matching entry count response control, to the given list.
2305   *
2306   * @param  lines     The list to which the lines should be added.
2307   * @param  c         The control to be formatted.
2308   * @param  prefix    The prefix to use for each line.
2309   * @param  maxWidth  The maximum length of each line in characters, including
2310   *                   the comment prefix and indent.
2311   */
2312  private static void addMatchingEntryCountResponseControl(
2313                           final List<String> lines, final Control c,
2314                           final String prefix, final int maxWidth)
2315  {
2316    final MatchingEntryCountResponseControl decoded;
2317    try
2318    {
2319      decoded = new MatchingEntryCountResponseControl(c.getOID(),
2320           c.isCritical(), c.getValue());
2321    }
2322    catch (final Exception e)
2323    {
2324      Debug.debugException(e);
2325      addGenericResponseControl(lines, c, prefix, maxWidth);
2326      return;
2327    }
2328
2329    wrap(lines, INFO_RESULT_UTILS_MATCHING_ENTRY_COUNT_HEADER.get(), prefix,
2330         maxWidth);
2331
2332    final String indentPrefix = prefix + "     ";
2333    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
2334         indentPrefix, maxWidth);
2335
2336    switch (decoded.getCountType())
2337    {
2338      case EXAMINED_COUNT:
2339        wrap(lines, INFO_RESULT_UTILS_MATCHING_ENTRY_COUNT_TYPE_EXAMINED.get(),
2340             indentPrefix, maxWidth);
2341        wrap(lines,
2342             INFO_RESULT_UTILS_MATCHING_ENTRY_COUNT_VALUE.get(
2343                  decoded.getCountValue()),
2344             indentPrefix, maxWidth);
2345        break;
2346
2347      case UNEXAMINED_COUNT:
2348        wrap(lines,
2349             INFO_RESULT_UTILS_MATCHING_ENTRY_COUNT_TYPE_UNEXAMINED.get(),
2350             indentPrefix, maxWidth);
2351        wrap(lines,
2352             INFO_RESULT_UTILS_MATCHING_ENTRY_COUNT_VALUE.get(
2353                  decoded.getCountValue()),
2354             indentPrefix, maxWidth);
2355        break;
2356
2357      case UPPER_BOUND:
2358        wrap(lines,
2359             INFO_RESULT_UTILS_MATCHING_ENTRY_COUNT_TYPE_UPPER_BOUND.get(),
2360             indentPrefix, maxWidth);
2361        wrap(lines,
2362             INFO_RESULT_UTILS_MATCHING_ENTRY_COUNT_VALUE.get(
2363                  decoded.getCountValue()),
2364             indentPrefix, maxWidth);
2365        break;
2366
2367      case UNKNOWN:
2368      default:
2369        wrap(lines, INFO_RESULT_UTILS_MATCHING_ENTRY_COUNT_TYPE_UNKNOWN.get(),
2370             indentPrefix, maxWidth);
2371        break;
2372    }
2373
2374    wrap(lines,
2375         INFO_RESULT_UTILS_MATCHING_ENTRY_COUNT_INDEXED.get(
2376              decoded.searchIndexed()),
2377         indentPrefix, maxWidth);
2378
2379    final List<String> debugInfo = decoded.getDebugInfo();
2380    if ((debugInfo != null) && (! debugInfo.isEmpty()))
2381    {
2382      wrap(lines, INFO_RESULT_UTILS_MATCHING_ENTRY_COUNT_DEBUG_HEADER.get(),
2383           indentPrefix, maxWidth);
2384      for (final String s : debugInfo)
2385      {
2386        wrap(lines, s, indentPrefix + "     ", maxWidth);
2387      }
2388    }
2389  }
2390
2391
2392
2393  /**
2394   * Adds a multi-line string representation of the provided control, which is
2395   * expected to be password policy response control, to the given list.
2396   *
2397   * @param  lines     The list to which the lines should be added.
2398   * @param  c         The control to be formatted.
2399   * @param  prefix    The prefix to use for each line.
2400   * @param  maxWidth  The maximum length of each line in characters, including
2401   *                   the comment prefix and indent.
2402   */
2403  private static void addPasswordPolicyResponseControl(
2404                           final List<String> lines, final Control c,
2405                           final String prefix, final int maxWidth)
2406  {
2407    final PasswordPolicyResponseControl decoded;
2408    try
2409    {
2410      decoded = new PasswordPolicyResponseControl(c.getOID(), c.isCritical(),
2411           c.getValue());
2412    }
2413    catch (final Exception e)
2414    {
2415      Debug.debugException(e);
2416      addGenericResponseControl(lines, c, prefix, maxWidth);
2417      return;
2418    }
2419
2420    wrap(lines, INFO_RESULT_UTILS_PW_POLICY_HEADER.get(), prefix, maxWidth);
2421
2422    final String indentPrefix = prefix + "     ";
2423    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
2424         indentPrefix, maxWidth);
2425
2426    final PasswordPolicyErrorType errorType = decoded.getErrorType();
2427    if (errorType == null)
2428    {
2429      wrap(lines, INFO_RESULT_UTILS_PW_POLICY_ERROR_TYPE_NONE.get(),
2430           indentPrefix, maxWidth);
2431    }
2432    else
2433    {
2434      wrap(lines,
2435           INFO_RESULT_UTILS_PW_POLICY_ERROR_TYPE.get(errorType.getName()),
2436           indentPrefix, maxWidth);
2437    }
2438
2439    final PasswordPolicyWarningType warningType = decoded.getWarningType();
2440    if (warningType == null)
2441    {
2442      wrap(lines, INFO_RESULT_UTILS_PW_POLICY_WARNING_TYPE_NONE.get(),
2443           indentPrefix, maxWidth);
2444    }
2445    else
2446    {
2447      wrap(lines,
2448           INFO_RESULT_UTILS_PW_POLICY_WARNING_TYPE.get(warningType.getName()),
2449           indentPrefix, maxWidth);
2450      wrap(lines,
2451           INFO_RESULT_UTILS_PW_POLICY_WARNING_VALUE.get(
2452                decoded.getWarningValue()),
2453           indentPrefix, maxWidth);
2454    }
2455  }
2456
2457
2458
2459  /**
2460   * Adds a multi-line string representation of the provided control, which is
2461   * expected to be a password validation details response control, to the given
2462   * list.
2463   *
2464   * @param  lines     The list to which the lines should be added.
2465   * @param  c         The control to be formatted.
2466   * @param  prefix    The prefix to use for each line.
2467   * @param  maxWidth  The maximum length of each line in characters, including
2468   *                   the comment prefix and indent.
2469   */
2470  private static void addPasswordValidationDetailsResponseControl(
2471                           final List<String> lines, final Control c,
2472                           final String prefix, final int maxWidth)
2473  {
2474    final PasswordValidationDetailsResponseControl decoded;
2475    try
2476    {
2477      decoded = new PasswordValidationDetailsResponseControl(c.getOID(),
2478           c.isCritical(), c.getValue());
2479    }
2480    catch (final Exception e)
2481    {
2482      Debug.debugException(e);
2483      addGenericResponseControl(lines, c, prefix, maxWidth);
2484      return;
2485    }
2486
2487    wrap(lines, INFO_RESULT_UTILS_PW_VALIDATION_DETAILS_HEADER.get(), prefix,
2488         maxWidth);
2489
2490    final String indentPrefix = prefix + "     ";
2491    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
2492         indentPrefix, maxWidth);
2493
2494    switch (decoded.getResponseType())
2495    {
2496      case VALIDATION_DETAILS:
2497        wrap(lines,
2498             INFO_RESULT_UTILS_PW_VALIDATION_DETAILS_RESULT_TYPE_RESULT.get(),
2499             indentPrefix, maxWidth);
2500
2501        final List<PasswordQualityRequirementValidationResult> results =
2502             decoded.getValidationResults();
2503        if (results != null)
2504        {
2505          for (final PasswordQualityRequirementValidationResult r : results)
2506          {
2507            wrap(lines,
2508                 INFO_RESULT_UTILS_PW_VALIDATION_DETAILS_PQR_HEADER.get(),
2509                 indentPrefix + "     ", maxWidth);
2510
2511            final String tripleIndentPrefix = indentPrefix + "          ";
2512            final PasswordQualityRequirement pqr = r.getPasswordRequirement();
2513
2514            final String description = pqr.getDescription();
2515            if (description != null)
2516            {
2517              wrap(lines,
2518                   INFO_RESULT_UTILS_PW_VALIDATION_DETAILS_PQR_DESC.get(
2519                        description),
2520                   tripleIndentPrefix, maxWidth);
2521            }
2522
2523            final String clientSideType = pqr.getClientSideValidationType();
2524            if (clientSideType != null)
2525            {
2526              wrap(lines,
2527                   INFO_RESULT_UTILS_PW_VALIDATION_DETAILS_PQR_TYPE.get(
2528                        clientSideType),
2529                   tripleIndentPrefix, maxWidth);
2530            }
2531
2532            final Map<String,String> properties =
2533                 pqr.getClientSideValidationProperties();
2534            if (properties != null)
2535            {
2536              for (final Map.Entry<String,String> e : properties.entrySet())
2537              {
2538                wrap(lines,
2539                     INFO_RESULT_UTILS_PW_VALIDATION_DETAILS_PQR_PROP.get(
2540                          e.getKey(), e.getValue()),
2541                     tripleIndentPrefix, maxWidth);
2542              }
2543            }
2544
2545            wrap(lines,
2546                 INFO_RESULT_UTILS_PW_VALIDATION_DETAILS_PQR_SATISFIED.get(
2547                      r.requirementSatisfied()),
2548                 tripleIndentPrefix, maxWidth);
2549
2550            final String additionalInfo = r.getAdditionalInfo();
2551            if (additionalInfo != null)
2552            {
2553              wrap(lines,
2554                   INFO_RESULT_UTILS_PW_VALIDATION_DETAILS_PQR_INFO.get(
2555                        additionalInfo),
2556                   tripleIndentPrefix, maxWidth);
2557            }
2558          }
2559        }
2560        break;
2561      case NO_PASSWORD_PROVIDED:
2562        wrap(lines,
2563             INFO_RESULT_UTILS_PW_VALIDATION_DETAILS_RESULT_TYPE_NO_PW.get(),
2564             indentPrefix, maxWidth);
2565        break;
2566      case MULTIPLE_PASSWORDS_PROVIDED:
2567        wrap(lines,
2568             INFO_RESULT_UTILS_PW_VALIDATION_DETAILS_RESULT_TYPE_MULTIPLE_PW.
2569                  get(),
2570             indentPrefix, maxWidth);
2571        break;
2572      case NO_VALIDATION_ATTEMPTED:
2573        wrap(lines,
2574             INFO_RESULT_UTILS_PW_VALIDATION_DETAILS_RESULT_TYPE_NO_VALIDATION.
2575                  get(),
2576             indentPrefix, maxWidth);
2577        break;
2578      default:
2579        wrap(lines,
2580             INFO_RESULT_UTILS_PW_VALIDATION_DETAILS_RESULT_TYPE_DEFAULT.get(
2581                  decoded.getResponseType().name()),
2582             indentPrefix, maxWidth);
2583        break;
2584    }
2585
2586    wrap(lines,
2587         INFO_RESULT_UTILS_PW_VALIDATION_DETAILS_MISSING_CURRENT.get(
2588              decoded.missingCurrentPassword()),
2589         indentPrefix, maxWidth);
2590    wrap(lines,
2591         INFO_RESULT_UTILS_PW_VALIDATION_DETAILS_MUST_CHANGE.get(
2592              decoded.mustChangePassword()),
2593         indentPrefix, maxWidth);
2594
2595    final Integer secondsUntilExpiration = decoded.getSecondsUntilExpiration();
2596    if (secondsUntilExpiration != null)
2597    {
2598      wrap(lines,
2599           INFO_RESULT_UTILS_PW_VALIDATION_DETAILS_SECONDS_TO_EXP.get(
2600                secondsUntilExpiration),
2601           indentPrefix, maxWidth);
2602    }
2603  }
2604
2605
2606
2607  /**
2608   * Adds a multi-line string representation of the provided control, which is
2609   * expected to be a soft delete response control, to the given list.
2610   *
2611   * @param  lines     The list to which the lines should be added.
2612   * @param  c         The control to be formatted.
2613   * @param  prefix    The prefix to use for each line.
2614   * @param  maxWidth  The maximum length of each line in characters, including
2615   *                   the comment prefix and indent.
2616   */
2617  private static void addSoftDeleteResponseControl(
2618                           final List<String> lines, final Control c,
2619                           final String prefix, final int maxWidth)
2620  {
2621    final SoftDeleteResponseControl decoded;
2622    try
2623    {
2624      decoded = new SoftDeleteResponseControl(c.getOID(), c.isCritical(),
2625           c.getValue());
2626    }
2627    catch (final Exception e)
2628    {
2629      Debug.debugException(e);
2630      addGenericResponseControl(lines, c, prefix, maxWidth);
2631      return;
2632    }
2633
2634    wrap(lines, INFO_RESULT_UTILS_SOFT_DELETE_HEADER.get(), prefix, maxWidth);
2635
2636    final String indentPrefix = prefix + "     ";
2637    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
2638         indentPrefix, maxWidth);
2639
2640    final String dn = decoded.getSoftDeletedEntryDN();
2641    if (dn != null)
2642    {
2643      wrap(lines, INFO_RESULT_UTILS_SOFT_DELETED_DN.get(dn), indentPrefix,
2644           maxWidth);
2645    }
2646  }
2647
2648
2649
2650  /**
2651   * Adds a multi-line string representation of the provided control, which is
2652   * expected to be a transaction settings response control, to the given list.
2653   *
2654   * @param  lines     The list to which the lines should be added.
2655   * @param  c         The control to be formatted.
2656   * @param  prefix    The prefix to use for each line.
2657   * @param  maxWidth  The maximum length of each line in characters, including
2658   *                   the comment prefix and indent.
2659   */
2660  private static void addTransactionSettingsResponseControl(
2661                           final List<String> lines, final Control c,
2662                           final String prefix, final int maxWidth)
2663  {
2664    final TransactionSettingsResponseControl decoded;
2665    try
2666    {
2667      decoded = new TransactionSettingsResponseControl(c.getOID(),
2668           c.isCritical(), c.getValue());
2669    }
2670    catch (final Exception e)
2671    {
2672      Debug.debugException(e);
2673      addGenericResponseControl(lines, c, prefix, maxWidth);
2674      return;
2675    }
2676
2677    wrap(lines, INFO_RESULT_UTILS_TXN_SETTINGS_HEADER.get(), prefix,
2678         maxWidth);
2679
2680    final String indentPrefix = prefix + "     ";
2681    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
2682         indentPrefix, maxWidth);
2683    wrap(lines,
2684         INFO_RESULT_UTILS_TXN_SETTINGS_NUM_CONFLICTS.get(
2685              decoded.getNumLockConflicts()),
2686         indentPrefix, maxWidth);
2687    wrap(lines,
2688         INFO_RESULT_UTILS_TXN_SETTINGS_BACKEND_LOCK_ACQUIRED.get(
2689              decoded.backendLockAcquired()),
2690         indentPrefix, maxWidth);
2691  }
2692
2693
2694
2695  /**
2696   * Adds a multi-line string representation of the provided control, which is
2697   * expected to be a uniqueness response control, to the given list.
2698   *
2699   * @param  lines     The list to which the lines should be added.
2700   * @param  c         The control to be formatted.
2701   * @param  prefix    The prefix to use for each line.
2702   * @param  maxWidth  The maximum length of each line in characters, including
2703   *                   the comment prefix and indent.
2704   */
2705  private static void addUniquenessResponseControl(
2706                           final List<String> lines, final Control c,
2707                           final String prefix, final int maxWidth)
2708  {
2709    final UniquenessResponseControl decoded;
2710    try
2711    {
2712      decoded = new UniquenessResponseControl(c.getOID(), c.isCritical(),
2713           c.getValue());
2714    }
2715    catch (final Exception e)
2716    {
2717      Debug.debugException(e);
2718      addGenericResponseControl(lines, c, prefix, maxWidth);
2719      return;
2720    }
2721
2722    wrap(lines, INFO_RESULT_UTILS_UNIQUENESS_HEADER.get(), prefix, maxWidth);
2723
2724    final String indentPrefix = prefix + "     ";
2725    wrap(lines, INFO_RESULT_UTILS_RESPONSE_CONTROL_OID.get(c.getOID()),
2726         indentPrefix, maxWidth);
2727    wrap(lines, INFO_RESULT_UTILS_UNIQUENESS_ID.get(decoded.getUniquenessID()),
2728         indentPrefix, maxWidth);
2729
2730    final String preCommitStatus;
2731    if (decoded.getPreCommitValidationPassed() == null)
2732    {
2733      preCommitStatus =
2734           INFO_RESULT_UTILS_UNIQUENESS_STATUS_VALUE_NOT_ATTEMPTED.get();
2735    }
2736    else if (decoded.getPreCommitValidationPassed() == Boolean.TRUE)
2737    {
2738      preCommitStatus = INFO_RESULT_UTILS_UNIQUENESS_STATUS_VALUE_PASSED.get();
2739    }
2740    else
2741    {
2742      preCommitStatus = INFO_RESULT_UTILS_UNIQUENESS_STATUS_VALUE_FAILED.get();
2743    }
2744    wrap(lines,
2745         INFO_RESULT_UTILS_UNIQUENESS_PRE_COMMIT_STATUS.get(preCommitStatus),
2746         indentPrefix, maxWidth);
2747
2748    final String postCommitStatus;
2749    if (decoded.getPostCommitValidationPassed() == null)
2750    {
2751      postCommitStatus =
2752           INFO_RESULT_UTILS_UNIQUENESS_STATUS_VALUE_NOT_ATTEMPTED.get();
2753    }
2754    else if (decoded.getPostCommitValidationPassed() == Boolean.TRUE)
2755    {
2756      postCommitStatus = INFO_RESULT_UTILS_UNIQUENESS_STATUS_VALUE_PASSED.get();
2757    }
2758    else
2759    {
2760      postCommitStatus = INFO_RESULT_UTILS_UNIQUENESS_STATUS_VALUE_FAILED.get();
2761    }
2762    wrap(lines,
2763         INFO_RESULT_UTILS_UNIQUENESS_POST_COMMIT_STATUS.get(postCommitStatus),
2764         indentPrefix, maxWidth);
2765
2766    final String message = decoded.getValidationMessage();
2767    if (message != null)
2768    {
2769      wrap(lines, INFO_RESULT_UTILS_UNIQUENESS_MESSAGE.get(message),
2770           indentPrefix, maxWidth);
2771    }
2772  }
2773
2774
2775
2776  /**
2777   * Creates a string that may be used as a prefix for all lines with the given
2778   * settings.
2779   *
2780   * @param  comment  Indicates whether to prefix each line with an octothorpe
2781   *                  to indicate that it is a comment.
2782   * @param  indent   The number of spaces to indent each line.
2783   *
2784   * @return  A string that may be used as a prefix for all lines with the given
2785   *          settings.
2786   */
2787  private static String createPrefix(final boolean comment, final int indent)
2788  {
2789    // Generate a prefix that will be used for every line.
2790    final StringBuilder buffer = new StringBuilder(indent + 2);
2791    if (comment)
2792    {
2793      buffer.append("# ");
2794    }
2795    for (int i=0; i < indent; i++)
2796    {
2797      buffer.append(' ');
2798    }
2799    return buffer.toString();
2800  }
2801
2802
2803
2804  /**
2805   * Adds a wrapped version of the provided string to the given list.
2806   *
2807   * @param  lines     The list to which the wrapped lines should be added.
2808   * @param  s         The string to be wrapped.
2809   * @param  prefix    The prefix to use at the beginning of each line.
2810   * @param  maxWidth  The maximum length of each line in characters.
2811   */
2812  private static void wrap(final List<String> lines, final String s,
2813                           final String prefix, final int maxWidth)
2814  {
2815    // If the maximum width is less than the prefix length + 20 characters, then
2816    // make it make that the new effective maximum width.
2817    final int minimumMaxWidth   = prefix.length() + 20;
2818    final int effectiveMaxWidth = Math.max(minimumMaxWidth, maxWidth);
2819
2820
2821    // If the prefix plus the provided string is within the maximum width, then
2822    // there's no need to do any wrapping.
2823    if ((prefix.length() + s.length()) <= effectiveMaxWidth)
2824    {
2825      lines.add(prefix + s);
2826      return;
2827    }
2828
2829
2830    // Wrap the provided string.  If it spans multiple lines, all lines except
2831    // the first will be indented an extra five spaces.
2832    final List<String> wrappedLines = StaticUtils.wrapLine(s,
2833         (maxWidth - prefix.length()),
2834         (maxWidth - prefix.length() - 5));
2835
2836
2837
2838    // Add the wrapped lines to the given list.
2839    for (int i=0; i < wrappedLines.size(); i++)
2840    {
2841      if (i > 0)
2842      {
2843        lines.add(prefix + "     " + wrappedLines.get(i));
2844      }
2845      else
2846      {
2847        lines.add(prefix + wrappedLines.get(i));
2848      }
2849    }
2850  }
2851
2852
2853
2854  /**
2855   * Adds the lines that comprise an LDIF representation of the provided entry
2856   * to the given list.
2857   *
2858   * @param  lines      The list to which the lines should be added.
2859   * @param  entry      The entry to be formatted.
2860   * @param  includeDN  Indicates whether to include the DN of the entry in the
2861   *                    resulting LDIF representation.
2862   * @param  prefix     The prefix to use at the beginning of each line.
2863   * @param  maxWidth   The maximum length of each line in characters.
2864   */
2865  private static void addLDIF(final List<String> lines, final Entry entry,
2866                              final boolean includeDN, final String prefix,
2867                              final int maxWidth)
2868  {
2869    // Never use a wrap column that is less than 20 characters.
2870    final int wrapColumn = Math.max(maxWidth - prefix.length(), 20);
2871
2872    if (includeDN)
2873    {
2874      for (final String s : entry.toLDIF(wrapColumn))
2875      {
2876        lines.add(prefix + s);
2877      }
2878    }
2879    else
2880    {
2881      final String[] ldifLinesWithDN;
2882      if (entry.getDN().length() > 10)
2883      {
2884        final Entry dup = entry.duplicate();
2885        dup.setDN("");
2886        ldifLinesWithDN = dup.toLDIF(wrapColumn);
2887      }
2888      else
2889      {
2890        ldifLinesWithDN = entry.toLDIF(wrapColumn);
2891      }
2892
2893      for (int i=1; i < ldifLinesWithDN.length; i++)
2894      {
2895        lines.add(prefix + ldifLinesWithDN[i]);
2896      }
2897    }
2898  }
2899}