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