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