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