001/*
002 * Copyright 2020 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 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) 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.extensions;
037
038
039
040import java.util.ArrayList;
041import java.util.List;
042
043import com.unboundid.asn1.ASN1Boolean;
044import com.unboundid.asn1.ASN1Element;
045import com.unboundid.asn1.ASN1Enumerated;
046import com.unboundid.asn1.ASN1Integer;
047import com.unboundid.asn1.ASN1OctetString;
048import com.unboundid.asn1.ASN1Sequence;
049import com.unboundid.ldap.sdk.Control;
050import com.unboundid.ldap.sdk.ExtendedRequest;
051import com.unboundid.ldap.sdk.ExtendedResult;
052import com.unboundid.ldap.sdk.IntermediateResponse;
053import com.unboundid.ldap.sdk.IntermediateResponseListener;
054import com.unboundid.ldap.sdk.LDAPException;
055import com.unboundid.ldap.sdk.LDAPConnection;
056import com.unboundid.ldap.sdk.LDAPRuntimeException;
057import com.unboundid.ldap.sdk.ResultCode;
058import com.unboundid.ldap.sdk.unboundidds.tasks.CollectSupportDataSecurityLevel;
059import com.unboundid.util.Debug;
060import com.unboundid.util.NotMutable;
061import com.unboundid.util.StaticUtils;
062import com.unboundid.util.ThreadSafety;
063import com.unboundid.util.ThreadSafetyLevel;
064import com.unboundid.util.Validator;
065
066import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
067
068
069
070/**
071 * This class provides an implementation of an extended request that may be used
072 * to invoke the collect-support data tool in a Ping Identity Directory Server
073 * and stream the output (using
074 * {@link CollectSupportDataOutputIntermediateResponse} messages) and the
075 * resulting support data archive (using
076 * {@link CollectSupportDataArchiveFragmentIntermediateResponse} messages)
077 * back to the client before the final
078 * {@link CollectSupportDataExtendedResult} response.
079 * <BR>
080 * <BLOCKQUOTE>
081 *   <B>NOTE:</B>  This class, and other classes within the
082 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
083 *   supported for use against Ping Identity, UnboundID, and
084 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
085 *   for proprietary functionality or for external specifications that are not
086 *   considered stable or mature enough to be guaranteed to work in an
087 *   interoperable way with other types of LDAP servers.
088 * </BLOCKQUOTE>
089 * <BR>
090 * The collect support data extended request has an OID of
091 * 1.3.6.1.4.1.30221.2.6.64 and a value with the following encoding:
092 * <BR>
093 * <PRE>
094 *   CollectSupportDataRequest ::= SEQUENCE {
095 *      archiveFileName                 [0]  OCTET STRING OPTIONAL,
096 *      encryptionPassphrase            [1]  OCTET STRING OPTIONAL,
097 *      includeExpensiveData            [2]  BOOLEAN DEFAULT FALSE,
098 *      includeReplicationStateDump     [3]  BOOLEAN DEFAULT FALSE,
099 *      includeBinaryFiles              [4]  BOOLEAN DEFAULT FALSE,
100 *      includeExtensionSource          [5]  BOOLEAN DEFAULT FALSE,
101 *      useSequentialMode               [6]  BOOLEAN DEFAULT FALSE,
102 *      securityLevel                   [7]  ENUMERATED {
103 *           none                            (0),
104 *           obscureSecrets                  (1),
105 *           maximum                         (2),
106 *           ... } DEFAULT obscureSecrets,
107 *      jstackCount                     [8]  INTEGER (0..MAX) DEFAULT 10,
108 *      reportCount                     [9]  INTEGER (0..MAX) DEFAULT 10,
109 *      reportIntervalSeconds           [10] INTEGER (1..MAX) DEFAULT 1,
110 *      logCaptureWindow                [11] CHOICE {
111 *           toolDefault                     [0] NULL,
112 *           durationMillis                  [1] INTEGER (0..MAX),
113 *           timeWindow                      [2] SEQUENCE {
114 *                startTime                       OCTET STRING,
115 *                endTime                         OCTET STRING OPTIONAL },
116 *           ... } DEFAULT default,
117 *      comment                         [12] OCTET STRING OPTIONAL,
118 *      proxyToServer                   [13] SEQUENCE OF {
119 *           address                         OCTET STRING,
120 *           port                            INTEGER (1..65535),
121 *           ... } OPTIONAL,
122 *      maximumFragmentSizeBytes        [1] INTEGER DEFAULT 1048576,
123 *      ... }
124 * </PRE>
125 * <BR><BR>
126 * Because the tool output and the support data archive will be streamed back to
127 * the client using intermediate response messages, the request must be
128 * configured with an intermediate response listener to gain access to that
129 * information.
130 *
131 * @see  CollectSupportDataExtendedResult
132 * @see  CollectSupportDataOutputIntermediateResponse
133 * @see  CollectSupportDataArchiveFragmentIntermediateResponse
134 * @see  CollectSupportDataSecurityLevel
135 * @see  CollectSupportDataLogCaptureWindow
136 */
137@NotMutable()
138@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
139public final class CollectSupportDataExtendedRequest
140       extends ExtendedRequest
141       implements IntermediateResponseListener
142{
143  /**
144   * The OID (1.3.6.1.4.1.30221.2.6.64) for the collect support data extended
145   * request.
146   */
147  public static final String COLLECT_SUPPORT_DATA_REQUEST_OID =
148       "1.3.6.1.4.1.30221.2.6.64";
149
150
151
152  /**
153   * The BER type for the request element that specifies the name to use for the
154   * archive file.
155   */
156  private static final byte TYPE_ARCHIVE_FILE_NAME = (byte) 0x80;
157
158
159
160  /**
161   * The BER type for the request element that specifies the passphrase to use
162   * to encrypt the contents of the support data archive.
163   */
164  static final byte TYPE_ENCRYPTION_PASSPHRASE = (byte) 0x81;
165
166
167
168  /**
169   * The BER type for the request element that indicates whether to include
170   * data that may be expensive to collect.
171   */
172  private static final byte TYPE_INCLUDE_EXPENSIVE_DATA = (byte) 0x82;
173
174
175
176  /**
177   * The BER type for the request element that indicates whether to include a
178   * replication state dump.
179   */
180  private static final byte TYPE_INCLUDE_REPLICATION_STATE_DUMP = (byte) 0x83;
181
182
183
184  /**
185   * The BER type for the request element that indicates whether to include
186   * binary files.
187   */
188  private static final byte TYPE_INCLUDE_BINARY_FILES = (byte) 0x84;
189
190
191
192  /**
193   * The BER type for the request element that indicates whether to include
194   * extension source code.
195   */
196  private static final byte TYPE_INCLUDE_EXTENSION_SOURCE = (byte) 0x85;
197
198
199
200  /**
201   * The BER type for the request element that indicates whether to collect
202   * information in sequential mode.
203   */
204  private static final byte TYPE_USE_SEQUENTIAL_MODE = (byte) 0x86;
205
206
207
208  /**
209   * The BER type for the request element that specifies the security level.
210   */
211  private static final byte TYPE_SECURITY_LEVEL = (byte) 0x87;
212
213
214
215  /**
216   * The BER type for the request element that specifies the number of jstack
217   * stack traces to include.
218   */
219  private static final byte TYPE_JSTACK_COUNT = (byte) 0x88;
220
221
222
223  /**
224   * The BER type for the request element that specifies the number intervals
225   * to collect from interval-based sampling tools.
226   */
227  private static final byte TYPE_REPORT_COUNT = (byte) 0x89;
228
229
230
231  /**
232   * The BER type for the request element that specifies the interval duration
233   * to use for interval-based sampling tools.
234   */
235  private static final byte TYPE_REPORT_INTERVAL_SECONDS = (byte) 0x8A;
236
237
238
239  /**
240   * The BER type for the request element that specifies the log capture window
241   * for the request.
242   */
243  private static final byte TYPE_LOG_CAPTURE_WINDOW = (byte) 0xAB;
244
245
246
247  /**
248   * The BER type for the request element that specifies a comment to include in
249   * the archive.
250   */
251  private static final byte TYPE_COMMENT = (byte) 0x8C;
252
253
254
255  /**
256   * The BER type for the request element that specifies the address and port
257   * to which the request should be forwarded.
258   */
259  private static final byte TYPE_PROXY_TO_SERVER = (byte) 0xAD;
260
261
262
263  /**
264   * The BER type for the request element that specifies the maximum archive
265   * fragment size.
266   */
267  private static final byte TYPE_MAXIMUM_FRAGMENT_SIZE_BYTES = (byte) 0x8E;
268
269
270
271  /**
272   * The integer value for the {@link CollectSupportDataSecurityLevel#NONE}
273   * security level.
274   */
275  private static final int SECURITY_LEVEL_VALUE_NONE = 0;
276
277
278
279  /**
280   * The integer value for the
281   * {@link CollectSupportDataSecurityLevel#OBSCURE_SECRETS} security level.
282   */
283  private static final int SECURITY_LEVEL_VALUE_OBSCURE_SECRETS = 1;
284
285
286
287  /**
288   * The integer value for the {@link CollectSupportDataSecurityLevel#MAXIMUM}
289   * security level.
290   */
291  private static final int SECURITY_LEVEL_VALUE_MAXIMUM = 2;
292
293
294
295  /**
296   * The serial version UID for this serializable class.
297   */
298  private static final long serialVersionUID = -8884596371195896085L;
299
300
301
302  // The passphrase to use to encrypt the contents of the support data archive.
303  private final ASN1OctetString encryptionPassphrase;
304
305  // Indicates whether to include binary files in the support data archive.
306  private final Boolean includeBinaryFiles;
307
308  // Indicates whether to include expensive data in the support data archive.
309  private final Boolean includeExpensiveData;
310
311  // Indicates whether to include third-party extension source code in the
312  // support data archive.
313  private final Boolean includeExtensionSource;
314
315  // Indicates whether to include a replication state dump in the support data
316  // archive.
317  private final Boolean includeReplicationStateDump;
318
319  // Indicates whether to capture information sequentially rather than in
320  // parallel.
321  private final Boolean useSequentialMode;
322
323  // The intermediate response listener that will be used for this operation.
324  private final CollectSupportDataIntermediateResponseListener
325       intermediateResponseListener;
326
327  // The log capture window that indicates how much log content to include in
328  // the support data archive.
329  private final CollectSupportDataLogCaptureWindow logCaptureWindow;
330
331  // The security level to use for data included in the support data archive.
332  private final CollectSupportDataSecurityLevel securityLevel;
333
334  // The number of jstacks to include in the support data archive.
335  private final Integer jstackCount;
336
337  // The maximum size, in bytes, of any support data archive fragment to include
338  // in a collect support data archive fragment intermediate response.
339  private final Integer maximumFragmentSizeBytes;
340
341  // The port of a backend Directory Server instance to which the collect
342  // support data extended request should be forwarded.
343  private final Integer proxyToServerPort;
344
345  // The report count to use for sampled metrics.
346  private final Integer reportCount;
347
348  // The report interval in seconds to use for sampled metrics.
349  private final Integer reportIntervalSeconds;
350
351  // The name (without any path information) the client intends to use for the
352  // support data archive file.
353  private final String archiveFileName;
354
355  // A comment to include in the support data archive.
356  private final String comment;
357
358  // The address of a backend Directory Server to which the collect support data
359  // extended request should be forwarded.
360  private final String proxyToServerAddress;
361
362
363
364  /**
365   * Creates a new instance of this extended request with the provided
366   * information.
367   *
368   * @param  properties                    The properties that should be used
369   *                                       for the collect support data extended
370   *                                       request.  It must not be
371   *                                       {@code null}.
372   * @param  intermediateResponseListener  The listener that will be used to
373   *                                       handle any intermediate response
374   *                                       messages that are received in the
375   *                                       course of processing the collect
376   *                                       support data extended request.  It
377   *                                       must not be {@code null}.
378   * @param  controls                      The controls to include in the
379   *                                       collect support data extended
380   *                                       request.  It may be {@code null} or
381   *                                       empty if no controls are needed.
382   */
383  public CollectSupportDataExtendedRequest(
384              final CollectSupportDataExtendedRequestProperties properties,
385              final CollectSupportDataIntermediateResponseListener
386                         intermediateResponseListener,
387              final Control... controls)
388  {
389    super(COLLECT_SUPPORT_DATA_REQUEST_OID, encodeValue(properties), controls);
390
391    Validator.ensureNotNullWithMessage(intermediateResponseListener,
392         "CollectSupportDataExtendedRequest.intermediateResponseListener " +
393              "must not be null.");
394    this.intermediateResponseListener = intermediateResponseListener;
395
396    archiveFileName = properties.getArchiveFileName();
397    encryptionPassphrase = properties.getEncryptionPassphrase();
398    includeBinaryFiles = properties.getIncludeBinaryFiles();
399    includeExpensiveData = properties.getIncludeExpensiveData();
400    includeExtensionSource = properties.getIncludeExtensionSource();
401    includeReplicationStateDump = properties.getIncludeReplicationStateDump();
402    useSequentialMode = properties.getUseSequentialMode();
403    logCaptureWindow = properties.getLogCaptureWindow();
404    securityLevel = properties.getSecurityLevel();
405    jstackCount = properties.getJStackCount();
406    reportCount = properties.getReportCount();
407    reportIntervalSeconds = properties.getReportIntervalSeconds();
408    maximumFragmentSizeBytes = properties.getMaximumFragmentSizeBytes();
409    proxyToServerPort = properties.getProxyToServerPort();
410    comment = properties.getComment();
411    proxyToServerAddress = properties.getProxyToServerAddress();
412
413    setIntermediateResponseListener(this);
414  }
415
416
417
418  /**
419   * Constructs an ASN.1 octet string suitable for use as the value of this
420   * collect support data extended request from the given set of properties.
421   *
422   * @param  properties  The properties that should be used to construct the
423   *                     extended request value.  It must not be {@code null}.
424   *
425   * @return  the ASN.1 octet string that was created.
426   */
427  private static ASN1OctetString encodeValue(
428               final CollectSupportDataExtendedRequestProperties properties)
429  {
430    final List<ASN1Element> elements = new ArrayList<>(20);
431
432    final String archiveFileName = properties.getArchiveFileName();
433    if (archiveFileName != null)
434    {
435      elements.add(new ASN1OctetString(TYPE_ARCHIVE_FILE_NAME,
436           archiveFileName));
437    }
438
439    final ASN1OctetString encryptionPassphrase =
440         properties.getEncryptionPassphrase();
441    if (encryptionPassphrase != null)
442    {
443      elements.add(encryptionPassphrase);
444    }
445
446    final Boolean includeExpensiveData = properties.getIncludeExpensiveData();
447    if (includeExpensiveData != null)
448    {
449      elements.add(new ASN1Boolean(TYPE_INCLUDE_EXPENSIVE_DATA,
450           includeExpensiveData));
451    }
452
453    final Boolean includeReplicationStateDump =
454         properties.getIncludeReplicationStateDump();
455    if (includeReplicationStateDump != null)
456    {
457      elements.add(new ASN1Boolean(TYPE_INCLUDE_REPLICATION_STATE_DUMP,
458           includeReplicationStateDump));
459    }
460
461    final Boolean includeBinaryFiles = properties.getIncludeBinaryFiles();
462    if (includeBinaryFiles != null)
463    {
464      elements.add(new ASN1Boolean(TYPE_INCLUDE_BINARY_FILES,
465           includeBinaryFiles));
466    }
467
468    final Boolean includeExtensionSource =
469         properties.getIncludeExtensionSource();
470    if (includeExtensionSource != null)
471    {
472      elements.add(new ASN1Boolean(TYPE_INCLUDE_EXTENSION_SOURCE,
473           includeExtensionSource));
474    }
475
476    final Boolean useSequentialMode = properties.getUseSequentialMode();
477    if (useSequentialMode != null)
478    {
479      elements.add(new ASN1Boolean(TYPE_USE_SEQUENTIAL_MODE,
480           useSequentialMode));
481    }
482
483    final CollectSupportDataSecurityLevel securityLevel =
484         properties.getSecurityLevel();
485    if (securityLevel != null)
486    {
487      final int securityLevelIntValue;
488      switch (securityLevel)
489      {
490        case NONE:
491          securityLevelIntValue = SECURITY_LEVEL_VALUE_NONE;
492          break;
493        case OBSCURE_SECRETS:
494          securityLevelIntValue = SECURITY_LEVEL_VALUE_OBSCURE_SECRETS;
495          break;
496        case MAXIMUM:
497          securityLevelIntValue = SECURITY_LEVEL_VALUE_MAXIMUM;
498          break;
499        default:
500          throw new LDAPRuntimeException(new LDAPException(
501               ResultCode.LOCAL_ERROR,
502               ERR_CSD_REQUEST_UNSUPPORTED_SECURITY_LEVEL.get(
503                    securityLevel.getName())));
504      }
505
506      elements.add(new ASN1Enumerated(TYPE_SECURITY_LEVEL,
507           securityLevelIntValue));
508    }
509
510    final Integer jstackCount = properties.getJStackCount();
511    if (jstackCount != null)
512    {
513      elements.add(new ASN1Integer(TYPE_JSTACK_COUNT, jstackCount));
514    }
515
516    final Integer reportCount = properties.getReportCount();
517    if (reportCount != null)
518    {
519      elements.add(new ASN1Integer(TYPE_REPORT_COUNT, reportCount));
520    }
521
522    final Integer reportIntervalSeconds =
523         properties.getReportIntervalSeconds();
524    if (reportIntervalSeconds != null)
525    {
526      elements.add(new ASN1Integer(TYPE_REPORT_INTERVAL_SECONDS,
527           reportIntervalSeconds));
528    }
529
530    final CollectSupportDataLogCaptureWindow logCaptureWindow =
531         properties.getLogCaptureWindow();
532    if (logCaptureWindow != null)
533    {
534      elements.add(new ASN1Element(TYPE_LOG_CAPTURE_WINDOW,
535           logCaptureWindow.encode().encode()));
536    }
537
538    final String comment = properties.getComment();
539    if (comment != null)
540    {
541      elements.add(new ASN1OctetString(TYPE_COMMENT, comment));
542    }
543
544    final String proxyToServerAddress = properties.getProxyToServerAddress();
545    if (proxyToServerAddress != null)
546    {
547      elements.add(new ASN1Sequence(TYPE_PROXY_TO_SERVER,
548           new ASN1OctetString(proxyToServerAddress),
549           new ASN1Integer(properties.getProxyToServerPort())));
550    }
551
552    final Integer maximumFragmentSizeBytes =
553         properties.getMaximumFragmentSizeBytes();
554    if (maximumFragmentSizeBytes != null)
555    {
556      elements.add(new ASN1Integer(TYPE_MAXIMUM_FRAGMENT_SIZE_BYTES,
557           maximumFragmentSizeBytes));
558    }
559
560    return new ASN1OctetString(new ASN1Sequence(elements).encode());
561  }
562
563
564
565  /**
566   * Creates a new collect support data extended request that is decoded from
567   * the provided generic extended request.
568   *
569   * @param  request                       The generic extended request to be
570   *                                       decoded as a collect support data
571   *                                       extended request.  It must not be
572   *                                       {@code null}.
573   * @param  intermediateResponseListener  The listener that will be used to
574   *                                       handle any intermediate response
575   *                                       messages that are received in the
576   *                                       course of processing the collect
577   *                                       support data extended request.  It
578   *                                       must not be {@code null}.
579   *
580   * @throws  LDAPException  If the provided extended request cannot be decoded
581   *                         as a valid collect support data extended request.
582   */
583  public CollectSupportDataExtendedRequest(final ExtendedRequest request,
584              final CollectSupportDataIntermediateResponseListener
585                         intermediateResponseListener)
586         throws LDAPException
587  {
588    super(request);
589
590    Validator.ensureNotNullWithMessage(intermediateResponseListener,
591         "CollectSupportDataExtendedRequest.intermediateResponseListener " +
592              "must not be null.");
593    this.intermediateResponseListener = intermediateResponseListener;
594
595    final ASN1OctetString value = request.getValue();
596    if (value == null)
597    {
598      throw new LDAPException(ResultCode.DECODING_ERROR,
599           ERR_CSD_REQUEST_DECODE_NO_VALUE.get());
600    }
601
602    try
603    {
604      ASN1OctetString encPassphrase = null;
605      Boolean includeExpensive = null;
606      Boolean includeReplication = null;
607      Boolean includeBinary = null;
608      Boolean includeSource = null;
609      Boolean sequentialMode = null;
610      CollectSupportDataSecurityLevel secLevel = null;
611      Integer jCount = null;
612      Integer rCount = null;
613      Integer rInterval = null;
614      CollectSupportDataLogCaptureWindow lcw = null;
615      String archiveName = null;
616      String commentStr = null;
617      String proxyToAddress = null;
618      Integer proxyToPort = null;
619      Integer maxFragmentSize = null;
620
621      final ASN1Sequence valueSequence =
622           ASN1Sequence.decodeAsSequence(value.getValue());
623      final ASN1Element[] elements = valueSequence.elements();
624      for (final ASN1Element e : elements)
625      {
626        switch (e.getType())
627        {
628          case TYPE_ARCHIVE_FILE_NAME:
629            archiveName = ASN1OctetString.decodeAsOctetString(e).stringValue();
630            break;
631          case TYPE_ENCRYPTION_PASSPHRASE:
632            encPassphrase = ASN1OctetString.decodeAsOctetString(e);
633            break;
634          case TYPE_INCLUDE_EXPENSIVE_DATA:
635            includeExpensive = ASN1Boolean.decodeAsBoolean(e).booleanValue();
636            break;
637          case TYPE_INCLUDE_REPLICATION_STATE_DUMP:
638            includeReplication = ASN1Boolean.decodeAsBoolean(e).booleanValue();
639            break;
640          case TYPE_INCLUDE_BINARY_FILES:
641            includeBinary = ASN1Boolean.decodeAsBoolean(e).booleanValue();
642            break;
643          case TYPE_INCLUDE_EXTENSION_SOURCE:
644            includeSource  = ASN1Boolean.decodeAsBoolean(e).booleanValue();
645            break;
646          case TYPE_USE_SEQUENTIAL_MODE:
647            sequentialMode  = ASN1Boolean.decodeAsBoolean(e).booleanValue();
648            break;
649          case TYPE_SECURITY_LEVEL:
650            final int secLevelIntValue =
651                 ASN1Enumerated.decodeAsEnumerated(e).intValue();
652            switch (secLevelIntValue)
653            {
654              case SECURITY_LEVEL_VALUE_NONE:
655                secLevel = CollectSupportDataSecurityLevel.NONE;
656                break;
657              case SECURITY_LEVEL_VALUE_OBSCURE_SECRETS:
658                secLevel = CollectSupportDataSecurityLevel.OBSCURE_SECRETS;
659                break;
660              case SECURITY_LEVEL_VALUE_MAXIMUM:
661                secLevel = CollectSupportDataSecurityLevel.MAXIMUM;
662                break;
663              default:
664                throw new LDAPException(ResultCode.DECODING_ERROR,
665                     ERR_CSD_REQUEST_DECODE_UNSUPPORTED_SECURITY_LEVEL.get(
666                          secLevelIntValue));
667            }
668            break;
669          case TYPE_JSTACK_COUNT:
670            jCount = ASN1Integer.decodeAsInteger(e).intValue();
671            break;
672          case TYPE_REPORT_COUNT:
673            rCount = ASN1Integer.decodeAsInteger(e).intValue();
674            break;
675          case TYPE_REPORT_INTERVAL_SECONDS:
676            rInterval = ASN1Integer.decodeAsInteger(e).intValue();
677            break;
678          case TYPE_LOG_CAPTURE_WINDOW:
679            final ASN1Element lcwElement = ASN1Element.decode(e.getValue());
680            try
681            {
682              lcw = CollectSupportDataLogCaptureWindow.decode(lcwElement);
683            }
684            catch (final Exception ex)
685            {
686              Debug.debugException(ex);
687              throw new LDAPException(ResultCode.DECODING_ERROR,
688                   ERR_CSD_REQUEST_DECODE_LCW_FAILED.get(
689                        StaticUtils.getExceptionMessage(ex)),
690                   ex);
691            }
692            break;
693          case TYPE_COMMENT:
694            commentStr = ASN1OctetString.decodeAsOctetString(e).stringValue();
695            break;
696          case TYPE_PROXY_TO_SERVER:
697            final ASN1Element[] proxyToElements =
698                 ASN1Sequence.decodeAsSequence(e).elements();
699            proxyToAddress = ASN1OctetString.decodeAsOctetString(
700                 proxyToElements[0]).stringValue();
701            proxyToPort = ASN1Integer.decodeAsInteger(
702                 proxyToElements[1]).intValue();
703            break;
704          case TYPE_MAXIMUM_FRAGMENT_SIZE_BYTES:
705            maxFragmentSize = ASN1Integer.decodeAsInteger(e).intValue();
706            break;
707        }
708      }
709
710      archiveFileName = archiveName;
711      encryptionPassphrase = encPassphrase;
712      includeExpensiveData = includeExpensive;
713      includeReplicationStateDump = includeReplication;
714      includeBinaryFiles = includeBinary;
715      includeExtensionSource = includeSource;
716      useSequentialMode = sequentialMode;
717      securityLevel = secLevel;
718      jstackCount = jCount;
719      reportCount = rCount;
720      reportIntervalSeconds = rInterval;
721      logCaptureWindow = lcw;
722      comment = commentStr;
723      proxyToServerAddress = proxyToAddress;
724      proxyToServerPort = proxyToPort;
725      maximumFragmentSizeBytes = maxFragmentSize;
726    }
727    catch (final LDAPException e)
728    {
729      Debug.debugException(e);
730      throw e;
731    }
732    catch (final Exception e)
733    {
734      Debug.debugException(e);
735      throw new LDAPException(ResultCode.DECODING_ERROR,
736           ERR_CSD_REQUEST_DECODE_ERROR.get(
737                StaticUtils.getExceptionMessage(e)),
738           e);
739    }
740  }
741
742
743
744  /**
745   * Retrieves the listener that will be notified when any output, archive
746   * fragment, or other types of intermediate response messages are received
747   * in response to this extended request.
748   *
749   * @return  The listener that will be notified when any output, archive
750   *          fragment, or other types of intermediate response messages are
751   *          in response to this extended request.
752   */
753  public CollectSupportDataIntermediateResponseListener
754              getCollectSupportDataIntermediateResponseListener()
755  {
756    return intermediateResponseListener;
757  }
758
759
760
761  /**
762   * Retrieves the name (without any path information) that the client intends
763   * to use for the support data archive file.
764   *
765   * @return  The name (without any path information) that the client intends to
766   *          use for the support data archive file, or {@code null} if the
767   *          server should generate an archive file name.
768   */
769  public String getArchiveFileName()
770  {
771    return archiveFileName;
772  }
773
774
775
776  /**
777   * Retrieves the passphrase that should be used to encrypt the contents of the
778   * support data archive.
779   *
780   * @return  The passphrase that should be used to encrypt the contents of the
781   *          support data archive, or {@code null} if the archive should not
782   *          be encrypted.
783   */
784  public ASN1OctetString getEncryptionPassphrase()
785  {
786    return encryptionPassphrase;
787  }
788
789
790
791  /**
792   * Retrieves the value of a flag that indicates whether the support data
793   * archive may include data that is potentially expensive to collect and
794   * could affect the performance or responsiveness of the server.
795   *
796   * @return  The value of a flag that indicates whether the support data
797   *          archive may include data that is potentially expensive to collect,
798   *          or {@code null} if the property should not be specified when the
799   *          task is created (in which case the server will use a default
800   *          behavior of excluding expensive data).
801   */
802  public Boolean getIncludeExpensiveData()
803  {
804    return includeExpensiveData;
805  }
806
807
808
809  /**
810   * Retrieves the value of a flag that indicates whether the support data
811   * archive may include a replication state dump, which may be several
812   * megabytes in size.
813   *
814   * @return  The value of a flag that indicates whether the support data
815   *          archive may include a replication state dump, or {@code null} if
816   *          the property should not be specified when the task is created (in
817   *          which case the server will use a default behavior of excluding the
818   *          state dump).
819   */
820  public Boolean getIncludeReplicationStateDump()
821  {
822    return includeReplicationStateDump;
823  }
824
825
826
827  /**
828   * Retrieves the value of a flag that indicates whether the support data
829   * archive may include binary files.
830   *
831   * @return  The value of a flag that indicates whether the support data
832   *          archive may include binary files, or {@code null} if the property
833   *          should not be specified when the task is created (in which case
834   *          the server will use a default behavior of excluding binary files).
835   */
836  public Boolean getIncludeBinaryFiles()
837  {
838    return includeBinaryFiles;
839  }
840
841
842
843  /**
844   * Retrieves the value of a flag that indicates whether the support data
845   * archive should include source code (if available) for any third-party
846   * extensions installed in the server.
847   *
848   * @return  The value of a flag that indicates whether the support data
849   *          archive should include source code (if available) for any
850   *          third-party extensions installed in the server, or {@code null} if
851   *          the property should not be specified when the task is created (in
852   *          which case the server will use a default behavior of excluding
853   *          extension source code).
854   */
855  public Boolean getIncludeExtensionSource()
856  {
857    return includeExtensionSource;
858  }
859
860
861
862  /**
863   * Retrieves the value of a flag that indicates whether the server should
864   * collect items for the support data archive in sequential mode rather than
865   * in parallel.  Collecting data in sequential mode may reduce the amount of
866   * memory consumed during the collection process, but it will take longer to
867   * complete.
868   *
869   * @return  The value of a flag that indicates whether the server should
870   *          collect items for the support data archive in sequential mode
871   *          rather than in parallel, or {@code null} if the property should
872   *          not be specified when the task is created (in which case the
873   *          server will default to capturing data in parallel).
874   */
875  public Boolean getUseSequentialMode()
876  {
877    return useSequentialMode;
878  }
879
880
881
882  /**
883   * Retrieves the security level that should be used to indicate which data
884   * should be obscured, redacted, or omitted from the support data archive.
885   *
886   * @return  The security level that should be used when creating the support
887   *          data archive, or {@code null} if the property should not be
888   *          specified when the task is created (in which case the server will
889   *          use a default security level).
890   */
891  public CollectSupportDataSecurityLevel getSecurityLevel()
892  {
893    return securityLevel;
894  }
895
896
897
898  /**
899   * Retrieves the number of times that the jstack utility should be invoked to
900   * obtain stack traces from all threads in the server.
901   *
902   * @return  The number of times that the jstack utility should be invoked to
903   *          obtain stack traces from all threads in the server, or
904   *          {@code null} if the property should not be specified when the task
905   *          is created (in which case the server will use a default count).
906   */
907  public Integer getJStackCount()
908  {
909    return jstackCount;
910  }
911
912
913
914  /**
915   * Retrieves the number of intervals that should be captured from tools that
916   * use interval-based sampling (e.g., vmstat, iostat, mpstat, etc.).
917   *
918   * @return  The number of intervals that should be captured from tools that
919   *          use interval-based sampling, or {@code null} if the property
920   *          should not be specified when the task is created (in which case
921   *          the server will use a default report count).
922   */
923  public Integer getReportCount()
924  {
925    return reportCount;
926  }
927
928
929
930  /**
931   * Retrieves the interval duration in seconds that should be used for tools
932   * that use interval-based sampling (e.g., vmstat, iostat, mpstat, etc.).
933   *
934   * @return  The interval duration in seconds that should be used for tools
935   *          that use interval-based sampling, or {@code null} if the property
936   *          should not be specified when the task is created (in which case
937   *          the server will use a default report interval).
938   */
939  public Integer getReportIntervalSeconds()
940  {
941    return reportIntervalSeconds;
942  }
943
944
945
946  /**
947   * Retrieves the log capture window object that indicates how much log content
948   * should be included in the support data archive.
949   *
950   * @return  The log capture window object that indicates how much log content
951   *          should be included in the support data archive, or {@code null}
952   *          if this should not be specified in the request and the server
953   *          should choose an appropriate amount of log content.
954   */
955  public CollectSupportDataLogCaptureWindow getLogCaptureWindow()
956  {
957    return logCaptureWindow;
958  }
959
960
961
962  /**
963   * Retrieves an additional comment that should be included in the support data
964   * archive.
965   *
966   * @return  An additional comment that should be included in the support data
967   *          archive, or {@code null} if no comment should be included.
968   */
969  public String getComment()
970  {
971    return comment;
972  }
973
974
975
976  /**
977   * Retrieves the address of the backend Directory Server to which the collect
978   * support data extended request should be forwarded.
979   *
980   * @return  The address of the backend Directory Server to which the collect
981   *          support data extended request should be forwarded, or {@code null}
982   *          if the request should be processed directly by the server that
983   *          receives it.
984   */
985  public String getProxyToServerAddress()
986  {
987    return proxyToServerAddress;
988  }
989
990
991
992  /**
993   * Retrieves the port of the backend Directory Server to which the collect
994   * support data extended request should be forwarded.
995   *
996   * @return  The port of the backend Directory Server to which the collect
997   *          support data extended request should be forwarded, or {@code null}
998   *          if the request should be processed directly by the server that
999   *          receives it.
1000   */
1001  public Integer getProxyToServerPort()
1002  {
1003    return proxyToServerPort;
1004  }
1005
1006
1007
1008  /**
1009   * Retrieves the maximum size, in bytes, that may be used for a support data
1010   * archive fragment returned in any single
1011   * {@link CollectSupportDataArchiveFragmentIntermediateResponse} message.
1012   *
1013   * @return  The maximum size, in bytes, that may be used for a support data
1014   *          archive fragment in any single archive fragment intermediate
1015   *          response message, or {@code null} if the server should use a
1016   *          default maximum fragment size.
1017   */
1018  public Integer getMaximumFragmentSizeBytes()
1019  {
1020    return maximumFragmentSizeBytes;
1021  }
1022
1023
1024
1025  /**
1026   * {@inheritDoc}
1027   */
1028  @Override()
1029  public CollectSupportDataExtendedResult process(
1030              final LDAPConnection connection, final int depth)
1031         throws LDAPException
1032  {
1033    final ExtendedResult extendedResponse = super.process(connection, depth);
1034    return new CollectSupportDataExtendedResult(extendedResponse);
1035  }
1036
1037
1038
1039  /**
1040   * {@inheritDoc}.
1041   */
1042  @Override()
1043  public CollectSupportDataExtendedRequest duplicate()
1044  {
1045    return duplicate(getControls());
1046  }
1047
1048
1049
1050  /**
1051   * {@inheritDoc}.
1052   */
1053  @Override()
1054  public CollectSupportDataExtendedRequest duplicate(final Control[] controls)
1055  {
1056    return new CollectSupportDataExtendedRequest(
1057         new CollectSupportDataExtendedRequestProperties(this),
1058         intermediateResponseListener, controls);
1059  }
1060
1061
1062
1063  /**
1064   * {@inheritDoc}
1065   */
1066  @Override()
1067  public String getExtendedRequestName()
1068  {
1069    return INFO_COLLECT_SUPPORT_DATA_REQUEST_NAME.get();
1070  }
1071
1072
1073
1074
1075  /**
1076   * {@inheritDoc}
1077   */
1078  @Override()
1079  public void intermediateResponseReturned(
1080                   final IntermediateResponse intermediateResponse)
1081  {
1082    switch (intermediateResponse.getOID())
1083    {
1084      case CollectSupportDataOutputIntermediateResponse.
1085           COLLECT_SUPPORT_DATA_OUTPUT_INTERMEDIATE_RESPONSE_OID:
1086        final CollectSupportDataOutputIntermediateResponse
1087             outputIntermediateResponse;
1088        try
1089        {
1090          outputIntermediateResponse =
1091               new CollectSupportDataOutputIntermediateResponse(
1092                    intermediateResponse);
1093        }
1094        catch (final Exception e)
1095        {
1096          Debug.debugException(e);
1097          intermediateResponseListener.handleOtherIntermediateResponse(
1098               intermediateResponse);
1099          return;
1100        }
1101
1102        intermediateResponseListener.handleOutputIntermediateResponse(
1103             outputIntermediateResponse);
1104        break;
1105
1106      case CollectSupportDataArchiveFragmentIntermediateResponse.
1107           COLLECT_SUPPORT_DATA_ARCHIVE_FRAGMENT_INTERMEDIATE_RESPONSE_OID:
1108        final CollectSupportDataArchiveFragmentIntermediateResponse
1109             fragmentIntermediateResponse;
1110        try
1111        {
1112          fragmentIntermediateResponse =
1113               new CollectSupportDataArchiveFragmentIntermediateResponse(
1114                    intermediateResponse);
1115        }
1116        catch (final Exception e)
1117        {
1118          Debug.debugException(e);
1119          intermediateResponseListener.handleOtherIntermediateResponse(
1120               intermediateResponse);
1121          return;
1122        }
1123
1124        intermediateResponseListener.handleArchiveFragmentIntermediateResponse(
1125             fragmentIntermediateResponse);
1126        break;
1127
1128      default:
1129        intermediateResponseListener.handleOtherIntermediateResponse(
1130             intermediateResponse);
1131    }
1132  }
1133
1134
1135
1136  /**
1137   * {@inheritDoc}
1138   */
1139  @Override()
1140  public void toString(final StringBuilder buffer)
1141  {
1142    buffer.append("CollectSupportDataExtendedRequest(oid='");
1143    buffer.append(getOID());
1144    buffer.append('\'');
1145
1146    if (archiveFileName != null)
1147    {
1148      buffer.append(", archiveFileName='");
1149      buffer.append(archiveFileName);
1150      buffer.append('\'');
1151    }
1152
1153    if (encryptionPassphrase != null)
1154    {
1155      buffer.append(", encryptionPassphrase='*****REDACTED*****'");
1156    }
1157
1158    if (includeExpensiveData != null)
1159    {
1160      buffer.append(", includeExpensiveData=");
1161      buffer.append(includeExpensiveData);
1162    }
1163
1164    if (includeReplicationStateDump != null)
1165    {
1166      buffer.append(", includeReplicationStateDump=");
1167      buffer.append(includeReplicationStateDump);
1168    }
1169
1170    if (includeBinaryFiles != null)
1171    {
1172      buffer.append(", includeBinaryFiles=");
1173      buffer.append(includeBinaryFiles);
1174    }
1175
1176    if (includeExtensionSource != null)
1177    {
1178      buffer.append(", includeExtensionSource=");
1179      buffer.append(includeExtensionSource);
1180    }
1181
1182    if (useSequentialMode != null)
1183    {
1184      buffer.append(", useSequentialMode=");
1185      buffer.append(useSequentialMode);
1186    }
1187
1188    if (securityLevel != null)
1189    {
1190      buffer.append(", securityLevel='");
1191      buffer.append(securityLevel.getName());
1192      buffer.append('\'');
1193    }
1194
1195    if (jstackCount != null)
1196    {
1197      buffer.append(", jstackCount=");
1198      buffer.append(jstackCount);
1199    }
1200
1201    if (reportCount != null)
1202    {
1203      buffer.append(", reportCount=");
1204      buffer.append(reportCount);
1205    }
1206
1207    if (reportIntervalSeconds != null)
1208    {
1209      buffer.append(", reportIntervalSeconds=");
1210      buffer.append(reportIntervalSeconds);
1211    }
1212
1213    if (logCaptureWindow != null)
1214    {
1215      buffer.append(", logCaptureWindow=");
1216      logCaptureWindow.toString(buffer);
1217    }
1218
1219    if (comment != null)
1220    {
1221      buffer.append(", comment='");
1222      buffer.append(comment);
1223      buffer.append('\'');
1224    }
1225
1226    if (proxyToServerAddress != null)
1227    {
1228      buffer.append(", proxyToServerAddress='");
1229      buffer.append(proxyToServerAddress);
1230      buffer.append('\'');
1231    }
1232
1233    if (proxyToServerPort != null)
1234    {
1235      buffer.append(", proxyToServerPort=");
1236      buffer.append(proxyToServerPort);
1237    }
1238
1239    if (maximumFragmentSizeBytes != null)
1240    {
1241      buffer.append(", maximumFragmentSizeBytes=");
1242      buffer.append(maximumFragmentSizeBytes);
1243    }
1244
1245    final Control[] controls = getControls();
1246    if (controls.length > 0)
1247    {
1248      buffer.append(", controls={");
1249      for (int i=0; i < controls.length; i++)
1250      {
1251        if (i > 0)
1252        {
1253          buffer.append(", ");
1254        }
1255
1256        buffer.append(controls[i]);
1257      }
1258      buffer.append('}');
1259    }
1260
1261    buffer.append(')');
1262  }
1263}