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