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