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