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