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