001/*
002 * Copyright 2020-2022 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2020-2022 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-2022 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.tasks;
037
038
039
040import java.util.ArrayList;
041import java.util.Arrays;
042import java.util.Collections;
043import java.util.LinkedHashMap;
044import java.util.List;
045import java.util.Map;
046import java.util.concurrent.TimeUnit;
047
048import com.unboundid.ldap.sdk.Attribute;
049import com.unboundid.ldap.sdk.Entry;
050import com.unboundid.util.Debug;
051import com.unboundid.util.NotMutable;
052import com.unboundid.util.NotNull;
053import com.unboundid.util.Nullable;
054import com.unboundid.util.StaticUtils;
055import com.unboundid.util.ThreadSafety;
056import com.unboundid.util.ThreadSafetyLevel;
057import com.unboundid.util.args.ArgumentException;
058import com.unboundid.util.args.DurationArgument;
059
060import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*;
061
062
063
064/**
065 * This class defines a Directory Server task that can be used to invoke the
066 * collect-support-data tool to capture a variety of information that may help
067 * monitor the state of the server or diagnose potential problems.
068 * <BR>
069 * <BLOCKQUOTE>
070 *   <B>NOTE:</B>  This class, and other classes within the
071 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
072 *   supported for use against Ping Identity, UnboundID, and
073 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
074 *   for proprietary functionality or for external specifications that are not
075 *   considered stable or mature enough to be guaranteed to work in an
076 *   interoperable way with other types of LDAP servers.
077 * </BLOCKQUOTE>
078 * <BR>
079 * The properties that are available for use with this type of task include:
080 * <UL>
081 *   <LI>The path (on the server filesystem) to which the support data archive
082 *       should be written.  If this is not provided, then the server will
083 *       determine an appropriate output file to use.  If this is provided and
084 *       refers to a file that exists, that file will be overwritten.  If this
085 *       is provided and refers to a directory that exists, then a file will
086 *       be created in that directory with a server-generated name.  If this
087 *       is provided and refers to a file that does not exist, then its parent
088 *       directory must exist, and a new file will be created with the specified
089 *       path.</LI>
090 *   <LI>The path (on the server filesystem) to a file containing the passphrase
091 *       to use to encrypt the contents of the support data archive.  If this is
092 *       not provided, then the support data archive will not be encrypted.</LI>
093 *   <LI>A flag that indicates whether to include data that may be expensive to
094 *       capture in the support data archive.  This information will not be
095 *       included by default.</LI>
096 *   <LI>A flag that indicates whether to include a replication state dump
097 *       (which may be several megabytes in size) in the support data
098 *       archive.  This information will not be included by default.</LI>
099 *   <LI>A flag that indicates whether to include binary files in the support
100 *       data archive.  Binary files will not be included by default.</LI>
101 *   <LI>A flag that indicates whether to include source code (if available) to
102 *       any third-party extensions installed in the server.  Extension source
103 *       code will not be included by default.</LI>
104 *   <LI>The data security level to use when redacting data to include in the
105 *       support data archive.  If this is not specified, the server will
106 *       select an appropriate security level.</LI>
107 *   <LI>A flag that indicates whether to capture items in sequential mode
108 *       (which will use less memory, but at the expense of taking longer to
109 *       complete) rather than in parallel.  Support data will be captured in
110 *       parallel by default.</LI>
111 *   <LI>The number and duration between intervals for use when collecting
112 *       output of tools (like vmstat, iostat, mpstat, etc.) that use
113 *       sampling over time.  If this is not provided, the server will use a
114 *       default count and interval.</LI>
115 *   <LI>The number of times to invoke the jstack utility to obtain a stack
116 *       trace of threads running in the JVM.  If this is not provided, the
117 *       server will use a default count.</LI>
118 *   <LI>The duration (the length of time before the time the task is invoked)
119 *       for log messages to be included in the support data archive.  If this
120 *       is not provided, the server will automatically select the amount of
121 *       log content to include.</LI>
122 *   <LI>The amount of data in kilobytes to capture from the beginning or end of
123 *       each log file.  If this is not provided, the server will automatically
124 *       select the amount of log content to include.</LI>
125 *   <LI>An optional comment to include in the support data archive.</LI>
126 * </UL>
127 */
128@NotMutable()
129@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
130public final class CollectSupportDataTask
131       extends Task
132{
133  /**
134   * The fully-qualified name of the Java class that is used for the collect
135   * support data task.
136   */
137  @NotNull static final String COLLECT_SUPPORT_DATA_TASK_CLASS =
138       "com.unboundid.directory.server.tasks.CollectSupportDataTask";
139
140
141
142  /**
143   * The prefix that will appear at the beginning of all attribute names used by
144   * the collect support data task.
145   */
146  @NotNull private static final String ATTR_PREFIX =
147       "ds-task-collect-support-data-";
148
149
150
151  /**
152   * The name of the attribute used to specify a comment to include in the
153   * support data archive.
154   */
155  @NotNull public static final String ATTR_COMMENT = ATTR_PREFIX + "comment";
156
157
158
159  /**
160   * The name of the attribute used to specify the path to a file containing the
161   * passphrase to use to encrypt the contents of the support data archive.
162   */
163  @NotNull public static final String ATTR_ENCRYPTION_PASSPHRASE_FILE =
164       ATTR_PREFIX + "encryption-passphrase-file";
165
166
167
168  /**
169   * The name of the attribute used to indicate whether the support data archive
170   * may include binary files that may otherwise have been omitted.
171   */
172  @NotNull public static final String ATTR_INCLUDE_BINARY_FILES =
173       ATTR_PREFIX + "include-binary-files";
174
175
176
177  /**
178   * The name of the attribute used to indicate whether the support data archive
179   * should include information that may be expensive to capture.
180   */
181  @NotNull public static final String ATTR_INCLUDE_EXPENSIVE_DATA =
182       ATTR_PREFIX + "include-expensive-data";
183
184
185
186  /**
187   * The name of the attribute used to indicate whether the support data archive
188   * may include the source code (if available) for any third-party extensions
189   * installed in the server.
190   */
191  @NotNull public static final String ATTR_INCLUDE_EXTENSION_SOURCE =
192       ATTR_PREFIX + "include-extension-source";
193
194
195
196  /**
197   * The name of the attribute used to indicate whether the support data archive
198   * should include a replication state dump (which may be several megabytes in
199   * size).
200   */
201  @NotNull public static final String ATTR_INCLUDE_REPLICATION_STATE_DUMP =
202       ATTR_PREFIX + "include-replication-state-dump";
203
204
205
206  /**
207   * The name of the attribute used to specify the number of times to invoke the
208   * jstack utility to capture server thread stack traces.
209   */
210  @NotNull public static final String ATTR_JSTACK_COUNT =
211       ATTR_PREFIX + "jstack-count";
212
213
214
215  /**
216   * The name of the attribute used to specify the length of time that should be
217   * covered by the log data included in the support data archive.
218   */
219  @NotNull public static final String ATTR_LOG_DURATION =
220       ATTR_PREFIX + "log-duration";
221
222
223
224  /**
225   * The name of the attribute used to specify the amount of data in kilobytes
226   * to capture from the beginning of each log file included in the support data
227   * archive.
228   */
229  @NotNull public static final String ATTR_LOG_FILE_HEAD_COLLECTION_SIZE_KB =
230       ATTR_PREFIX + "log-file-head-collection-size-kb";
231
232
233
234  /**
235   * The name of the attribute used to specify the amount of data in kilobytes
236   * to capture from the end of each log file included in the support data
237   * archive.
238   */
239  @NotNull public static final String ATTR_LOG_FILE_TAIL_COLLECTION_SIZE_KB =
240       ATTR_PREFIX + "log-file-tail-collection-size-kb";
241
242
243
244  /**
245   * The name of the attribute used to specify the path to which the support
246   * data archive should be written.
247   */
248  @NotNull public static final String ATTR_OUTPUT_PATH =
249       ATTR_PREFIX + "output-path";
250
251
252
253  /**
254   * The name of the attribute used to specify the number of intervals to
255   * capture for tools that capture multiple samples.
256   */
257  @NotNull public static final String ATTR_REPORT_COUNT =
258       ATTR_PREFIX + "report-count";
259
260
261
262  /**
263   * The name of the attribute used to specify the length of time, in seconds,
264   * between samples collected from tools that capture multiple samples.
265   */
266  @NotNull public static final String ATTR_REPORT_INTERVAL_SECONDS =
267       ATTR_PREFIX + "report-interval-seconds";
268
269
270
271  /**
272   *The name of the attribute used to specify the minimum age of previous
273   * support data archives that should be retained.
274   */
275  @NotNull public static final String ATTR_RETAIN_PREVIOUS_ARCHIVE_AGE =
276       ATTR_PREFIX + "retain-previous-support-data-archive-age";
277
278
279
280  /**
281   *The name of the attribute used to specify the minimum number of previous
282   * support data archives that should be retained.
283   */
284  @NotNull public static final String ATTR_RETAIN_PREVIOUS_ARCHIVE_COUNT =
285       ATTR_PREFIX + "retain-previous-support-data-archive-count";
286
287
288
289  /**
290   * The name of the attribute used to specify the security level to use for
291   * information added to the support data archive.
292   */
293  @NotNull public static final String ATTR_SECURITY_LEVEL =
294       ATTR_PREFIX + "security-level";
295
296
297
298  /**
299   * The name of the attribute used to indicate whether to collect items
300   * sequentially rather than in parallel.
301   */
302  @NotNull public static final String ATTR_USE_SEQUENTIAL_MODE =
303       ATTR_PREFIX + "use-sequential-mode";
304
305
306
307  /**
308   * The name of the object class used in collect support data task entries.
309   */
310  @NotNull public static final String OC_COLLECT_SUPPORT_DATA_TASK =
311       "ds-task-collect-support-data";
312
313
314
315  /**
316   * The task property that will be used for the comment.
317   */
318  @NotNull static final TaskProperty PROPERTY_COMMENT =
319     new TaskProperty(ATTR_COMMENT, INFO_CSD_DISPLAY_NAME_COMMENT.get(),
320          INFO_CSD_DESCRIPTION_COMMENT.get(), String.class, false, false,
321          false);
322
323
324
325  /**
326   * The task property that will be used for the encryption passphrase file.
327   */
328  @NotNull static final TaskProperty PROPERTY_ENCRYPTION_PASSPHRASE_FILE =
329     new TaskProperty(ATTR_ENCRYPTION_PASSPHRASE_FILE,
330          INFO_CSD_DISPLAY_NAME_ENC_PW_FILE.get(),
331          INFO_CSD_DESCRIPTION_ENC_PW_FILE.get(), String.class, false, false,
332          false);
333
334
335
336  /**
337   * The task property that will be used for the include binary files flag.
338   */
339  @NotNull static final TaskProperty PROPERTY_INCLUDE_BINARY_FILES =
340     new TaskProperty(ATTR_INCLUDE_BINARY_FILES,
341          INFO_CSD_DISPLAY_NAME_INCLUDE_BINARY_FILES.get(),
342          INFO_CSD_DESCRIPTION_INCLUDE_BINARY_FILES.get(), Boolean.class, false,
343          false, false);
344
345
346
347  /**
348   * The task property that will be used for the include expensive data flag.
349   */
350  @NotNull static final TaskProperty PROPERTY_INCLUDE_EXPENSIVE_DATA =
351     new TaskProperty(ATTR_INCLUDE_EXPENSIVE_DATA,
352          INFO_CSD_DISPLAY_NAME_INCLUDE_EXPENSIVE_DATA.get(),
353          INFO_CSD_DESCRIPTION_INCLUDE_EXPENSIVE_DATA.get(), Boolean.class,
354          false, false, false);
355
356
357
358  /**
359   * The task property that will be used for the include extension source flag.
360   */
361  @NotNull static final TaskProperty PROPERTY_INCLUDE_EXTENSION_SOURCE =
362     new TaskProperty(ATTR_INCLUDE_EXTENSION_SOURCE,
363          INFO_CSD_DISPLAY_NAME_INCLUDE_EXTENSION_SOURCE.get(),
364          INFO_CSD_DESCRIPTION_INCLUDE_EXTENSION_SOURCE.get(), Boolean.class,
365          false, false, false);
366
367
368
369  /**
370   * The task property that will be used for the include replication state dump
371   * flag.
372   */
373  @NotNull static final TaskProperty PROPERTY_INCLUDE_REPLICATION_STATE_DUMP =
374     new TaskProperty(ATTR_INCLUDE_REPLICATION_STATE_DUMP,
375          INFO_CSD_DISPLAY_NAME_INCLUDE_REPLICATION_STATE_DUMP.get(),
376          INFO_CSD_DESCRIPTION_INCLUDE_REPLICATION_STATE_DUMP.get(),
377          Boolean.class, false, false, false);
378
379
380
381  /**
382   * The task property that will be used for the jstack count.
383   */
384  @NotNull static final TaskProperty PROPERTY_JSTACK_COUNT =
385     new TaskProperty(ATTR_JSTACK_COUNT,
386          INFO_CSD_DISPLAY_NAME_JSTACK_COUNT.get(),
387          INFO_CSD_DESCRIPTION_JSTACK_COUNT.get(),
388          Long.class, false, false, false);
389
390
391
392  /**
393   * The task property that will be used for the log duration.
394   */
395  @NotNull static final TaskProperty PROPERTY_LOG_DURATION =
396     new TaskProperty(ATTR_LOG_DURATION,
397          INFO_CSD_DISPLAY_NAME_LOG_DURATION.get(),
398          INFO_CSD_DESCRIPTION_LOG_DURATION.get(),
399          String.class, false, false, false);
400
401
402
403  /**
404   * The task property that will be used for the log head size.
405   */
406  @NotNull static final TaskProperty PROPERTY_LOG_FILE_HEAD_COLLECTION_SIZE_KB =
407     new TaskProperty(ATTR_LOG_FILE_HEAD_COLLECTION_SIZE_KB,
408          INFO_CSD_DISPLAY_NAME_LOG_HEAD_SIZE_KB.get(),
409          INFO_CSD_DESCRIPTION_LOG_HEAD_SIZE_KB.get(),
410          Long.class, false, false, false);
411
412
413
414  /**
415   * The task property that will be used for the log tail size.
416   */
417  @NotNull static final TaskProperty PROPERTY_LOG_FILE_TAIL_COLLECTION_SIZE_KB =
418     new TaskProperty(ATTR_LOG_FILE_TAIL_COLLECTION_SIZE_KB,
419          INFO_CSD_DISPLAY_NAME_LOG_TAIL_SIZE_KB.get(),
420          INFO_CSD_DESCRIPTION_LOG_TAIL_SIZE_KB.get(),
421          Long.class, false, false, false);
422
423
424
425  /**
426   * The task property that will be used for the output path.
427   */
428  @NotNull static final TaskProperty PROPERTY_OUTPUT_PATH =
429     new TaskProperty(ATTR_OUTPUT_PATH,
430          INFO_CSD_DISPLAY_NAME_OUTPUT_PATH.get(),
431          INFO_CSD_DESCRIPTION_OUTPUT_PATH.get(),
432          String.class, false, false, false);
433
434
435
436  /**
437   * The task property that will be used for the report count.
438   */
439  @NotNull static final TaskProperty PROPERTY_REPORT_COUNT =
440     new TaskProperty(ATTR_REPORT_COUNT,
441          INFO_CSD_DISPLAY_NAME_REPORT_COUNT.get(),
442          INFO_CSD_DESCRIPTION_REPORT_COUNT.get(),
443          Long.class, false, false, false);
444
445
446
447  /**
448   * The task property that will be used for the report interval.
449   */
450  @NotNull static final TaskProperty PROPERTY_REPORT_INTERVAL_SECONDS =
451     new TaskProperty(ATTR_REPORT_INTERVAL_SECONDS,
452          INFO_CSD_DISPLAY_NAME_REPORT_INTERVAL.get(),
453          INFO_CSD_DESCRIPTION_REPORT_INTERVAL.get(),
454          Long.class, false, false, false);
455
456
457
458  /**
459   * The task property that will be used for the retain previous support data
460   * archive age.
461   */
462  @NotNull static final TaskProperty PROPERTY_RETAIN_PREVIOUS_ARCHIVE_AGE =
463     new TaskProperty(ATTR_RETAIN_PREVIOUS_ARCHIVE_AGE,
464          INFO_CSD_DISPLAY_NAME_RETAIN_PREVIOUS_ARCHIVE_AGE.get(),
465          INFO_CSD_DESCRIPTION_RETAIN_PREVIOUS_ARCHIVE_AGE.get(),
466          String.class, false, false, false);
467
468
469
470  /**
471   * The task property that will be used for the retain previous support data
472   * archive count.
473   */
474  @NotNull static final TaskProperty PROPERTY_RETAIN_PREVIOUS_ARCHIVE_COUNT =
475     new TaskProperty(ATTR_RETAIN_PREVIOUS_ARCHIVE_COUNT,
476          INFO_CSD_DISPLAY_NAME_RETAIN_PREVIOUS_ARCHIVE_COUNT.get(),
477          INFO_CSD_DESCRIPTION_RETAIN_PREVIOUS_ARCHIVE_COUNT.get(),
478          Long.class, false, false, false);
479
480
481
482  /**
483   * The task property that will be used for the security level.
484   */
485  @NotNull static final TaskProperty PROPERTY_SECURITY_LEVEL =
486     new TaskProperty(ATTR_SECURITY_LEVEL,
487          INFO_CSD_DISPLAY_NAME_SECURITY_LEVEL.get(),
488          INFO_CSD_DESCRIPTION_SECURITY_LEVEL.get(
489               CollectSupportDataSecurityLevel.NONE.getName(),
490               CollectSupportDataSecurityLevel.OBSCURE_SECRETS.getName(),
491               CollectSupportDataSecurityLevel.MAXIMUM.getName()),
492          String.class, false, false, false,
493          new Object[]
494          {
495            CollectSupportDataSecurityLevel.NONE.getName(),
496            CollectSupportDataSecurityLevel.OBSCURE_SECRETS.getName(),
497            CollectSupportDataSecurityLevel.MAXIMUM.getName()
498          });
499
500
501
502  /**
503   * The task property that will be used for the use sequential mode flag.
504   */
505  @NotNull static final TaskProperty PROPERTY_USE_SEQUENTIAL_MODE =
506     new TaskProperty(ATTR_USE_SEQUENTIAL_MODE,
507          INFO_CSD_DISPLAY_NAME_USE_SEQUENTIAL_MODE.get(),
508          INFO_CSD_DESCRIPTION_USE_SEQUENTIAL_MODE.get(),
509          Boolean.class, false, false, false);
510
511
512
513  /**
514   * The serial version UID for this serializable class.
515   */
516  private static final long serialVersionUID = -3414981969721886291L;
517
518
519
520  // Indicates whether to include binary files in the support data archive.
521  @Nullable private final Boolean includeBinaryFiles;
522
523  // Indicates whether to include expensive data in the support data archive.
524  @Nullable private final Boolean includeExpensiveData;
525
526  // Indicates whether to include third-party extension source code in the
527  // support data archive.
528  @Nullable private final Boolean includeExtensionSource;
529
530  // Indicates whether to include a replication state dump in the support data
531  // archive.
532  @Nullable private final Boolean includeReplicationStateDump;
533
534  // Indicates whether to capture information sequentially rather than in
535  // parallel.
536  @Nullable private final Boolean useSequentialMode;
537
538  // The security level to use for data included in the support data archive.
539  @Nullable private final CollectSupportDataSecurityLevel securityLevel;
540
541  // The number of jstacks to include in the support data archive.
542  @Nullable private final Integer jstackCount;
543
544  // The amount of data in kilobytes to capture from the beginning of each log
545  // file.
546  @Nullable private final Integer logFileHeadCollectionSizeKB;
547
548  // The amount of data in kilobytes to capture from the end of each log file.
549  @Nullable private final Integer logFileTailCollectionSizeKB;
550
551  // The report count to use for sampled metrics.
552  @Nullable private final Integer reportCount;
553
554  // The report interval, in seconds, to use for sampled metrics.
555  @Nullable private final Integer reportIntervalSeconds;
556
557  // The minimum number of existing support data archives that should be
558  // retained.
559  @Nullable private final Integer retainPreviousSupportDataArchiveCount;
560
561  // A comment to include in the support data archive.
562  @Nullable private final String comment;
563
564  // The path to the encryption passphrase file.
565  @Nullable private final String encryptionPassphraseFile;
566
567  // A string representation of the log duration to capture.
568  @Nullable private final String logDuration;
569
570  // The path to which the support data archive should be written.
571  @Nullable private final String outputPath;
572
573  // The minimum age for existing support data archives that should be retained.
574  @Nullable private final String retainPreviousSupportDataArchiveAge;
575
576
577
578  /**
579   * Creates a new collect support data task instance that will use default
580   * settings for all properties.  This instance may be used to invoke the
581   * task, but it can also be used for obtaining general information about this
582   * task, including the task name, description, and supported properties.
583   */
584  public CollectSupportDataTask()
585  {
586    this(new CollectSupportDataTaskProperties());
587  }
588
589
590
591  /**
592   * Creates a new collect support data task instance using the provided
593   * properties.
594   *
595   * @param  properties  The properties to use to create the collect support
596   *                     data task.  It must not be {@code null}.
597   */
598  public CollectSupportDataTask(
599              @NotNull final CollectSupportDataTaskProperties properties)
600  {
601    super(properties.getTaskID(), COLLECT_SUPPORT_DATA_TASK_CLASS,
602         properties.getScheduledStartTime(), properties.getDependencyIDs(),
603         properties.getFailedDependencyAction(), properties.getNotifyOnStart(),
604         properties.getNotifyOnCompletion(), properties.getNotifyOnSuccess(),
605         properties.getNotifyOnError(), properties.getAlertOnStart(),
606         properties.getAlertOnSuccess(), properties.getAlertOnError());
607
608    includeBinaryFiles = properties.getIncludeBinaryFiles();
609    includeExpensiveData = properties.getIncludeExpensiveData();
610    includeExtensionSource = properties.getIncludeExtensionSource();
611    includeReplicationStateDump = properties.getIncludeReplicationStateDump();
612    useSequentialMode = properties.getUseSequentialMode();
613    securityLevel = properties.getSecurityLevel();
614    jstackCount = properties.getJStackCount();
615    logFileHeadCollectionSizeKB = properties.getLogFileHeadCollectionSizeKB();
616    logFileTailCollectionSizeKB = properties.getLogFileTailCollectionSizeKB();
617    reportCount = properties.getReportCount();
618    reportIntervalSeconds = properties.getReportIntervalSeconds();
619    retainPreviousSupportDataArchiveCount =
620         properties.getRetainPreviousSupportDataArchiveCount();
621    comment = properties.getComment();
622    encryptionPassphraseFile = properties.getEncryptionPassphraseFile();
623    logDuration = properties.getLogDuration();
624    outputPath = properties.getOutputPath();
625    retainPreviousSupportDataArchiveAge =
626         properties.getRetainPreviousSupportDataArchiveAge();
627  }
628
629
630
631  /**
632   * Creates a new collect support data task from the provided entry.
633   *
634   * @param  entry  The entry to use to create this collect support data task.
635   *
636   * @throws  TaskException  If the provided entry cannot be parsed as a collect
637   *                         support data task entry.
638   */
639  public CollectSupportDataTask(@NotNull final Entry entry)
640         throws TaskException
641  {
642    super(entry);
643
644    includeBinaryFiles =
645         entry.getAttributeValueAsBoolean(ATTR_INCLUDE_BINARY_FILES);
646    includeExpensiveData =
647         entry.getAttributeValueAsBoolean(ATTR_INCLUDE_EXPENSIVE_DATA);
648    includeExtensionSource =
649         entry.getAttributeValueAsBoolean(ATTR_INCLUDE_EXTENSION_SOURCE);
650    includeReplicationStateDump =
651         entry.getAttributeValueAsBoolean(ATTR_INCLUDE_REPLICATION_STATE_DUMP);
652    useSequentialMode =
653         entry.getAttributeValueAsBoolean(ATTR_USE_SEQUENTIAL_MODE);
654
655    jstackCount = entry.getAttributeValueAsInteger(ATTR_JSTACK_COUNT);
656    logFileHeadCollectionSizeKB = entry.getAttributeValueAsInteger(
657         ATTR_LOG_FILE_HEAD_COLLECTION_SIZE_KB);
658    logFileTailCollectionSizeKB = entry.getAttributeValueAsInteger(
659         ATTR_LOG_FILE_TAIL_COLLECTION_SIZE_KB);
660    reportCount = entry.getAttributeValueAsInteger(ATTR_REPORT_COUNT);
661    reportIntervalSeconds =
662         entry.getAttributeValueAsInteger(ATTR_REPORT_INTERVAL_SECONDS);
663    retainPreviousSupportDataArchiveCount =
664         entry.getAttributeValueAsInteger(ATTR_RETAIN_PREVIOUS_ARCHIVE_COUNT);
665
666    comment = entry.getAttributeValue(ATTR_COMMENT);
667    encryptionPassphraseFile =
668         entry.getAttributeValue(ATTR_ENCRYPTION_PASSPHRASE_FILE);
669    outputPath = entry.getAttributeValue(ATTR_OUTPUT_PATH);
670
671    final String securityLevelStr =
672         entry.getAttributeValue(ATTR_SECURITY_LEVEL);
673    if (securityLevelStr == null)
674    {
675      securityLevel = null;
676    }
677    else
678    {
679      securityLevel = CollectSupportDataSecurityLevel.forName(securityLevelStr);
680      if (securityLevel == null)
681      {
682        throw new TaskException(ERR_CSD_ENTRY_INVALID_SECURITY_LEVEL.get(
683             entry.getDN(), securityLevelStr, ATTR_SECURITY_LEVEL,
684             CollectSupportDataSecurityLevel.NONE.getName(),
685             CollectSupportDataSecurityLevel.OBSCURE_SECRETS.getName(),
686             CollectSupportDataSecurityLevel.MAXIMUM.getName()));
687      }
688    }
689
690    logDuration = entry.getAttributeValue(ATTR_LOG_DURATION);
691    if (logDuration != null)
692    {
693      try
694      {
695        DurationArgument.parseDuration(logDuration, TimeUnit.MILLISECONDS);
696      }
697      catch (final Exception e)
698      {
699        Debug.debugException(e);
700        throw new TaskException(
701             ERR_CSD_ENTRY_INVALID_DURATION.get(entry.getDN(), logDuration,
702                  ATTR_LOG_DURATION),
703             e);
704      }
705    }
706
707    retainPreviousSupportDataArchiveAge =
708         entry.getAttributeValue(ATTR_RETAIN_PREVIOUS_ARCHIVE_AGE);
709    if (retainPreviousSupportDataArchiveAge != null)
710    {
711      try
712      {
713        DurationArgument.parseDuration(retainPreviousSupportDataArchiveAge,
714             TimeUnit.MILLISECONDS);
715      }
716      catch (final Exception e)
717      {
718        Debug.debugException(e);
719        throw new TaskException(
720             ERR_CSD_ENTRY_INVALID_DURATION.get(entry.getDN(),
721                  retainPreviousSupportDataArchiveAge,
722                  ATTR_RETAIN_PREVIOUS_ARCHIVE_AGE),
723             e);
724      }
725    }
726  }
727
728
729
730  /**
731   * Creates a new collect support data task from the provided set of task
732   * properties.
733   *
734   * @param  properties  The set of task properties and their corresponding
735   *                     values to use for the task.  It must not be
736   *                     {@code null}.
737   *
738   * @throws  TaskException  If the provided set of properties cannot be used to
739   *                         create a valid collect support data task.
740   */
741  public CollectSupportDataTask(
742              @NotNull final Map<TaskProperty,List<Object>> properties)
743         throws TaskException
744  {
745    super(COLLECT_SUPPORT_DATA_TASK_CLASS, properties);
746
747    Boolean includeBinary = null;
748    Boolean includeExpensive = null;
749    Boolean includeReplicationState = null;
750    Boolean includeSource = null;
751    Boolean sequentialMode = null;
752    CollectSupportDataSecurityLevel secLevel = null;
753    Integer logHeadSizeKB = null;
754    Integer logTailSizeKB = null;
755    Integer numJStacks = null;
756    Integer numReports = null;
757    Integer reportIntervalSecs = null;
758    Integer retainCount = null;
759    String commentStr = null;
760    String encPWFile = null;
761    String logDurationStr = null;
762    String outputPathStr = null;
763    String retainAge = null;
764
765    for (final Map.Entry<TaskProperty,List<Object>> entry :
766         properties.entrySet())
767    {
768      final TaskProperty p = entry.getKey();
769      final String attrName = StaticUtils.toLowerCase(p.getAttributeName());
770      final List<Object> values = entry.getValue();
771
772      if (attrName.equals(ATTR_INCLUDE_BINARY_FILES))
773      {
774        includeBinary = parseBoolean(p, values, includeBinary);
775      }
776      else if (attrName.equals(ATTR_INCLUDE_EXPENSIVE_DATA))
777      {
778        includeExpensive = parseBoolean(p, values, includeExpensive);
779      }
780      else if (attrName.equals(ATTR_INCLUDE_REPLICATION_STATE_DUMP))
781      {
782        includeReplicationState =
783             parseBoolean(p, values, includeReplicationState);
784      }
785      else if (attrName.equals(ATTR_INCLUDE_EXTENSION_SOURCE))
786      {
787        includeSource = parseBoolean(p, values, includeSource);
788      }
789      else if (attrName.equals(ATTR_USE_SEQUENTIAL_MODE))
790      {
791        sequentialMode = parseBoolean(p, values, sequentialMode);
792      }
793      else if (attrName.equals(ATTR_SECURITY_LEVEL))
794      {
795        final String secLevelStr = parseString(p, values,
796             getSecurityLevelName(secLevel));
797        secLevel = CollectSupportDataSecurityLevel.forName(secLevelStr);
798      }
799      else if (attrName.equals(ATTR_JSTACK_COUNT))
800      {
801        numJStacks = parseLong(p, values,
802             getIntegerAsLong(numJStacks)).intValue();
803      }
804      else if (attrName.equals(ATTR_LOG_FILE_HEAD_COLLECTION_SIZE_KB))
805      {
806        logHeadSizeKB = parseLong(p, values,
807             getIntegerAsLong(logHeadSizeKB)).intValue();
808      }
809      else if (attrName.equals(ATTR_LOG_FILE_TAIL_COLLECTION_SIZE_KB))
810      {
811        logTailSizeKB = parseLong(p, values,
812             getIntegerAsLong(logTailSizeKB)).intValue();
813      }
814      else if (attrName.equals(ATTR_REPORT_COUNT))
815      {
816        numReports = parseLong(p, values,
817             getIntegerAsLong(numReports)).intValue();
818      }
819      else if (attrName.equals(ATTR_REPORT_INTERVAL_SECONDS))
820      {
821        reportIntervalSecs = parseLong(p, values,
822             getIntegerAsLong(reportIntervalSecs)).intValue();
823      }
824      else if (attrName.equals(ATTR_COMMENT))
825      {
826        commentStr = parseString(p, values, commentStr);
827      }
828      else if (attrName.equals(ATTR_ENCRYPTION_PASSPHRASE_FILE))
829      {
830        encPWFile = parseString(p, values, encPWFile);
831      }
832      else if (attrName.equals(ATTR_LOG_DURATION))
833      {
834        logDurationStr = parseString(p, values, logDurationStr);
835        try
836        {
837          DurationArgument.parseDuration(logDurationStr, TimeUnit.MILLISECONDS);
838        }
839        catch (final Exception e)
840        {
841          Debug.debugException(e);
842          throw new TaskException(
843               ERR_CSD_PROPERTY_INVALID_DURATION.get(logDurationStr,
844                    ATTR_LOG_DURATION),
845               e);
846        }
847      }
848      else if (attrName.equals(ATTR_OUTPUT_PATH))
849      {
850        outputPathStr = parseString(p, values, outputPathStr);
851      }
852      else if (attrName.equals(ATTR_RETAIN_PREVIOUS_ARCHIVE_COUNT))
853      {
854        retainCount = parseLong(p, values,
855             getIntegerAsLong(retainCount)).intValue();
856      }
857      else if (attrName.equals(ATTR_RETAIN_PREVIOUS_ARCHIVE_AGE))
858      {
859        retainAge = parseString(p, values, retainAge);
860        try
861        {
862          DurationArgument.parseDuration(retainAge, TimeUnit.MILLISECONDS);
863        }
864        catch (final Exception e)
865        {
866          Debug.debugException(e);
867          throw new TaskException(
868               ERR_CSD_PROPERTY_INVALID_DURATION.get(retainAge,
869                    ATTR_RETAIN_PREVIOUS_ARCHIVE_AGE),
870               e);
871        }
872      }
873    }
874
875    includeBinaryFiles = includeBinary;
876    includeExpensiveData = includeExpensive;
877    includeReplicationStateDump = includeReplicationState;
878    includeExtensionSource = includeSource;
879    useSequentialMode = sequentialMode;
880    securityLevel = secLevel;
881    jstackCount = numJStacks;
882    logFileHeadCollectionSizeKB = logHeadSizeKB;
883    logFileTailCollectionSizeKB = logTailSizeKB;
884    reportCount = numReports;
885    reportIntervalSeconds = reportIntervalSecs;
886    retainPreviousSupportDataArchiveCount = retainCount;
887    comment = commentStr;
888    encryptionPassphraseFile = encPWFile;
889    logDuration = logDurationStr;
890    outputPath = outputPathStr;
891    retainPreviousSupportDataArchiveAge = retainAge;
892  }
893
894
895
896  /**
897   * Retrieves the name of the provided security level.
898   *
899   * @param  securityLevel  The security level for which to retrieve the name.
900   *                        It may be {@code null}.
901   *
902   * @return  The name of the provided security level, or {@code null} if the
903   *          provided security level is {@code null}.
904   */
905  @Nullable()
906  static String getSecurityLevelName(
907       @Nullable final CollectSupportDataSecurityLevel securityLevel)
908  {
909    if (securityLevel == null)
910    {
911      return null;
912    }
913    else
914    {
915      return securityLevel.getName();
916    }
917  }
918
919
920
921  /**
922   * Retrieves the value of the provided {@code Integer} object as a
923   * {@code Long}.
924   *
925   * @param  i  The {@code Integer} value to convert to a {@code Long}.  It may
926   *            be {@code null}.
927   *
928   * @return  The value of the provided {@code Integer} object as a
929   *          {@code Long}, or {@code null} if the provided value was
930   *          {@code null}.
931   */
932  @Nullable()
933  static Long getIntegerAsLong(@Nullable final Integer i)
934  {
935    if (i == null)
936    {
937      return null;
938    }
939    else
940    {
941      return i.longValue();
942    }
943  }
944
945
946
947  /**
948   * {@inheritDoc}
949   */
950  @Override()
951  @NotNull()
952  public String getTaskName()
953  {
954    return INFO_CSD_TASK_NAME.get();
955  }
956
957
958
959  /**
960   * {@inheritDoc}
961   */
962  @Override()
963  @NotNull()
964  public String getTaskDescription()
965  {
966    return INFO_CSD_TASK_DESCRIPTION.get();
967  }
968
969
970
971  /**
972   * Retrieves the path on the server filesystem to which the support data
973   * archive should be written.
974   *
975   * @return  The path on the server filesystem to which the support data
976   *          archive should be written, or {@code null} if no value has been
977   *          specified for the property.
978   */
979  @Nullable()
980  public String getOutputPath()
981  {
982    return outputPath;
983  }
984
985
986
987  /**
988   * Retrieves the path on the server filesystem to a file that contains the
989   * passphrase to use to encrypt the support data archive.
990   *
991   * @return  The path on the server filesystem to a file that contains the
992   *          passphrase to use to encrypt the support data archive, or
993   *          {@code null} if no value has been specified for the property, and
994   *          the support data archive should not be encrypted.
995   */
996  @Nullable()
997  public String getEncryptionPassphraseFile()
998  {
999    return encryptionPassphraseFile;
1000  }
1001
1002
1003
1004  /**
1005   * Retrieves the value of a flag that indicates whether the support data
1006   * archive may include data that is potentially expensive to collect and
1007   * could affect the performance or responsiveness of the server.
1008   *
1009   * @return  The value of a flag that indicates whether the support data
1010   *          archive may include data that is potentially expensive to collect,
1011   *          or {@code null} if the property should not be specified when the
1012   *          task is created (in which case the server will use a default
1013   *          behavior of excluding expensive data).
1014   */
1015  @Nullable()
1016  public Boolean getIncludeExpensiveData()
1017  {
1018    return includeExpensiveData;
1019  }
1020
1021
1022
1023  /**
1024   * Retrieves the value of a flag that indicates whether the support data
1025   * archive may include a replication state dump, which may be several
1026   * megabytes in size.
1027   *
1028   * @return  The value of a flag that indicates whether the support data
1029   *          archive may include a replication state dump, or {@code null} if
1030   *          the property should not be specified when the task is created (in
1031   *          which case the server will use a default behavior of excluding the
1032   *          state dump).
1033   */
1034  @Nullable()
1035  public Boolean getIncludeReplicationStateDump()
1036  {
1037    return includeReplicationStateDump;
1038  }
1039
1040
1041
1042  /**
1043   * Retrieves the value of a flag that indicates whether the support data
1044   * archive may include binary files.
1045   *
1046   * @return  The value of a flag that indicates whether the support data
1047   *          archive may include binary files, or {@code null} if the property
1048   *          should not be specified when the task is created (in which case
1049   *          the server will use a default behavior of excluding binary files).
1050   */
1051  @Nullable()
1052  public Boolean getIncludeBinaryFiles()
1053  {
1054    return includeBinaryFiles;
1055  }
1056
1057
1058
1059  /**
1060   * Retrieves the value of a flag that indicates whether the support data
1061   * archive should include source code (if available) for any third-party
1062   * extensions installed in the server.
1063   *
1064   * @return  The value of a flag that indicates whether the support data
1065   *          archive should include source code (if available) for any
1066   *          third-party extensions installed in the server, or {@code null} if
1067   *          the property should not be specified when the task is created (in
1068   *          which case the server will use a default behavior of excluding
1069   *          extension source code).
1070   */
1071  @Nullable()
1072  public Boolean getIncludeExtensionSource()
1073  {
1074    return includeExtensionSource;
1075  }
1076
1077
1078
1079  /**
1080   * Retrieves the value of a flag that indicates whether the server should
1081   * collect items for the support data archive in sequential mode rather than
1082   * in parallel.  Collecting data in sequential mode may reduce the amount of
1083   * memory consumed during the collection process, but it will take longer to
1084   * complete.
1085   *
1086   * @return  The value of a flag that indicates whether the server should
1087   *          collect items for the support data archive in sequential mode
1088   *          rather than in parallel, or {@code null} if the property should
1089   *          not be specified when the task is created (in which case the
1090   *          server will default to capturing data in parallel).
1091   */
1092  @Nullable()
1093  public Boolean getUseSequentialMode()
1094  {
1095    return useSequentialMode;
1096  }
1097
1098
1099
1100  /**
1101   * Retrieves the security level that should be used to indicate which data
1102   * should be obscured, redacted, or omitted from the support data archive.
1103   *
1104   * @return  The security level that should be used when creating the support
1105   *          data archive, or {@code null} if the property should not be
1106   *          specified when the task is created (in which case the server will
1107   *          use a default security level).
1108   */
1109  @Nullable()
1110  public CollectSupportDataSecurityLevel getSecurityLevel()
1111  {
1112    return securityLevel;
1113  }
1114
1115
1116
1117  /**
1118   * Retrieves the number of intervals that should be captured from tools that
1119   * use interval-based sampling (e.g., vmstat, iostat, mpstat, etc.).
1120   *
1121   * @return  The number of intervals that should be captured from tools that
1122   *          use interval-based sampling, or {@code null} if the property
1123   *          should not be specified when the task is created (in which case
1124   *          the server will use a default report count).
1125   */
1126  @Nullable()
1127  public Integer getReportCount()
1128  {
1129    return reportCount;
1130  }
1131
1132
1133
1134  /**
1135   * Retrieves the interval duration in seconds that should be used for tools
1136   * that use interval-based sampling (e.g., vmstat, iostat, mpstat, etc.).
1137   *
1138   * @return  The interval duration in seconds that should be used for tools
1139   *          that use interval-based sampling, or {@code null} if the property
1140   *          should not be specified when the task is created (in which case
1141   *          the server will use a default report interval).
1142   */
1143  @Nullable()
1144  public Integer getReportIntervalSeconds()
1145  {
1146    return reportIntervalSeconds;
1147  }
1148
1149
1150
1151  /**
1152   * Retrieves the number of times that the jstack utility should be invoked to
1153   * obtain stack traces from all threads in the server.
1154   *
1155   * @return  The number of times that the jstack utility should be invoked to
1156   *          obtain stack traces from all threads in the server, or
1157   *          {@code null} if the property should not be specified when the task
1158   *          is created (in which case the server will use a default count).
1159   */
1160  @Nullable()
1161  public Integer getJStackCount()
1162  {
1163    return jstackCount;
1164  }
1165
1166
1167
1168  /**
1169   * Retrieves a string representation of the duration (up until the time that
1170   * the collect support data task is invoked) of log content that should be
1171   * included in the support data archive.
1172   *
1173   * @return  A string representation of the duration of log content that should
1174   *          be included in the support data archive, or {@code null} if the
1175   *          property should not be specified when the task is created (in
1176   *          which case the server will use a default behavior for selecting
1177   *          the amount of log content to include).
1178   */
1179  @Nullable()
1180  public String getLogDuration()
1181  {
1182    return logDuration;
1183  }
1184
1185
1186
1187  /**
1188   * Retrieves the amount of data in kilobytes to capture from the beginning of
1189   * each log file that should be included in the support data archive.
1190   *
1191   * @return  The amount of data in kilobytes to capture from the beginning of
1192   *          each log file that should be included in the support data archive,
1193   *          or {@code null} if the property should not be specified when the
1194   *          task is created (in which case the server will determine an
1195   *          appropriate amount of log content to include).
1196   */
1197  @Nullable()
1198  public Integer getLogFileHeadCollectionSizeKB()
1199  {
1200    return logFileHeadCollectionSizeKB;
1201  }
1202
1203
1204
1205  /**
1206   * Retrieves the amount of data in kilobytes to capture from the end of each
1207   * log file that should be included in the support data archive.
1208   *
1209   * @return  The amount of data in kilobytes to capture from the end of each
1210   *          log file that should be included in the support data archive, or
1211   *          {@code null} if the property should not be specified when the task
1212   *          is created (in which case the server will determine an
1213   *          appropriate amount of log content to include).
1214   */
1215  @Nullable()
1216  public Integer getLogFileTailCollectionSizeKB()
1217  {
1218    return logFileTailCollectionSizeKB;
1219  }
1220
1221
1222
1223  /**
1224   * Retrieves a parsed value of the log duration in milliseconds.
1225   *
1226   * @return  A parsed value of the log duration in milliseconds or {@code null}
1227   *          if no log duration is set.
1228   *
1229   * @throws  TaskException  If the log duration value cannot be parsed as a
1230   *                         valid duration.
1231   */
1232  @Nullable()
1233  public Long getLogDurationMillis()
1234         throws TaskException
1235  {
1236    if (logDuration == null)
1237    {
1238      return null;
1239    }
1240
1241    try
1242    {
1243      return DurationArgument.parseDuration(logDuration, TimeUnit.MILLISECONDS);
1244    }
1245    catch (final ArgumentException e)
1246    {
1247      Debug.debugException(e);
1248      throw new TaskException(e.getMessage(), e);
1249    }
1250  }
1251
1252
1253
1254  /**
1255   * Retrieves an additional comment that should be included in the support data
1256   * archive.
1257   *
1258   * @return  An additional comment that should be included in the support data
1259   *          archive, or {@code null} if no comment should be included.
1260   */
1261  @Nullable()
1262  public String getComment()
1263  {
1264    return comment;
1265  }
1266
1267
1268
1269  /**
1270   * Retrieves the minimum number of existing support data archives that should
1271   * be retained.
1272   *
1273   * @return  The minimum number of existing support data archives that should
1274   *          be retained, or {@code null} if there is no minimum retain count.
1275   */
1276  @Nullable()
1277  public Integer getRetainPreviousSupportDataArchiveCount()
1278  {
1279    return retainPreviousSupportDataArchiveCount;
1280  }
1281
1282
1283
1284  /**
1285   * Retrieves the minimum age of existing support data archives that should be
1286   * retained.
1287   *
1288   * @return  The minimum age of existing support data archives that should
1289   *          be retained, or {@code null} if there is no minimum retain age.
1290   */
1291  @Nullable()
1292  public String getRetainPreviousSupportDataArchiveAge()
1293  {
1294    return retainPreviousSupportDataArchiveAge;
1295  }
1296
1297
1298
1299  /**
1300   * Retrieves a parsed value of the retain previous support data archive age in
1301   * milliseconds.
1302   *
1303   * @return  A parsed value of the retain previous support data archive age in
1304   *          milliseconds or {@code null} if no retain age is set.
1305   *
1306   * @throws  TaskException  If the retain age value cannot be parsed as a valid
1307   *                         duration.
1308   */
1309  @Nullable()
1310  public Long getRetainPreviousSupportDataArchiveAgeMillis()
1311         throws TaskException
1312  {
1313    if (retainPreviousSupportDataArchiveAge == null)
1314    {
1315      return null;
1316    }
1317
1318    try
1319    {
1320      return DurationArgument.parseDuration(
1321           retainPreviousSupportDataArchiveAge, TimeUnit.MILLISECONDS);
1322    }
1323    catch (final ArgumentException e)
1324    {
1325      Debug.debugException(e);
1326      throw new TaskException(e.getMessage(), e);
1327    }
1328  }
1329
1330
1331
1332  /**
1333   * {@inheritDoc}
1334   */
1335  @Override()
1336  @NotNull()
1337  protected List<String> getAdditionalObjectClasses()
1338  {
1339    return Collections.singletonList(OC_COLLECT_SUPPORT_DATA_TASK);
1340  }
1341
1342
1343
1344  /**
1345   * {@inheritDoc}
1346   */
1347  @Override()
1348  @NotNull()
1349  protected List<Attribute> getAdditionalAttributes()
1350  {
1351    final List<Attribute> attrList = new ArrayList<>(15);
1352
1353    if (outputPath != null)
1354    {
1355      attrList.add(new Attribute(ATTR_OUTPUT_PATH, outputPath));
1356    }
1357
1358    if (encryptionPassphraseFile != null)
1359    {
1360      attrList.add(new Attribute(ATTR_ENCRYPTION_PASSPHRASE_FILE,
1361           encryptionPassphraseFile));
1362    }
1363
1364    if (includeExpensiveData != null)
1365    {
1366      attrList.add(new Attribute(ATTR_INCLUDE_EXPENSIVE_DATA,
1367           includeExpensiveData ? "TRUE" : "FALSE"));
1368    }
1369
1370    if (includeReplicationStateDump != null)
1371    {
1372      attrList.add(new Attribute(ATTR_INCLUDE_REPLICATION_STATE_DUMP,
1373           includeReplicationStateDump ? "TRUE" : "FALSE"));
1374    }
1375
1376    if (includeBinaryFiles != null)
1377    {
1378      attrList.add(new Attribute(ATTR_INCLUDE_BINARY_FILES,
1379           includeBinaryFiles ? "TRUE" : "FALSE"));
1380    }
1381
1382    if (includeExtensionSource != null)
1383    {
1384      attrList.add(new Attribute(ATTR_INCLUDE_EXTENSION_SOURCE,
1385           includeExtensionSource ? "TRUE" : "FALSE"));
1386    }
1387
1388    if (useSequentialMode != null)
1389    {
1390      attrList.add(new Attribute(ATTR_USE_SEQUENTIAL_MODE,
1391           useSequentialMode ? "TRUE" : "FALSE"));
1392    }
1393
1394    if (securityLevel != null)
1395    {
1396      attrList.add(new Attribute(ATTR_SECURITY_LEVEL, securityLevel.getName()));
1397    }
1398
1399    if (jstackCount != null)
1400    {
1401      attrList.add(new Attribute(ATTR_JSTACK_COUNT,
1402           String.valueOf(jstackCount)));
1403    }
1404
1405    if (reportCount != null)
1406    {
1407      attrList.add(new Attribute(ATTR_REPORT_COUNT,
1408           String.valueOf(reportCount)));
1409    }
1410
1411    if (reportIntervalSeconds != null)
1412    {
1413      attrList.add(new Attribute(ATTR_REPORT_INTERVAL_SECONDS,
1414           String.valueOf(reportIntervalSeconds)));
1415    }
1416
1417    if (logDuration != null)
1418    {
1419      attrList.add(new Attribute(ATTR_LOG_DURATION, logDuration));
1420    }
1421
1422    if (logFileHeadCollectionSizeKB != null)
1423    {
1424      attrList.add(new Attribute(ATTR_LOG_FILE_HEAD_COLLECTION_SIZE_KB,
1425           String.valueOf(logFileHeadCollectionSizeKB)));
1426    }
1427
1428    if (logFileTailCollectionSizeKB != null)
1429    {
1430      attrList.add(new Attribute(ATTR_LOG_FILE_TAIL_COLLECTION_SIZE_KB,
1431           String.valueOf(logFileTailCollectionSizeKB)));
1432    }
1433
1434    if (comment != null)
1435    {
1436      attrList.add(new Attribute(ATTR_COMMENT, comment));
1437    }
1438
1439    if (retainPreviousSupportDataArchiveCount != null)
1440    {
1441      attrList.add(new Attribute(ATTR_RETAIN_PREVIOUS_ARCHIVE_COUNT,
1442           String.valueOf(retainPreviousSupportDataArchiveCount)));
1443    }
1444
1445    if (retainPreviousSupportDataArchiveAge != null)
1446    {
1447      attrList.add(new Attribute(ATTR_RETAIN_PREVIOUS_ARCHIVE_AGE,
1448           retainPreviousSupportDataArchiveAge));
1449    }
1450
1451    return attrList;
1452  }
1453
1454
1455
1456  /**
1457   * {@inheritDoc}
1458   */
1459  @Override()
1460  @NotNull()
1461  public List<TaskProperty> getTaskSpecificProperties()
1462  {
1463    return Collections.unmodifiableList(Arrays.asList(
1464         PROPERTY_OUTPUT_PATH,
1465         PROPERTY_ENCRYPTION_PASSPHRASE_FILE,
1466         PROPERTY_INCLUDE_EXPENSIVE_DATA,
1467         PROPERTY_INCLUDE_REPLICATION_STATE_DUMP,
1468         PROPERTY_INCLUDE_BINARY_FILES,
1469         PROPERTY_INCLUDE_EXTENSION_SOURCE,
1470         PROPERTY_USE_SEQUENTIAL_MODE,
1471         PROPERTY_SECURITY_LEVEL,
1472         PROPERTY_JSTACK_COUNT,
1473         PROPERTY_REPORT_COUNT,
1474         PROPERTY_REPORT_INTERVAL_SECONDS,
1475         PROPERTY_LOG_DURATION,
1476         PROPERTY_LOG_FILE_HEAD_COLLECTION_SIZE_KB,
1477         PROPERTY_LOG_FILE_TAIL_COLLECTION_SIZE_KB,
1478         PROPERTY_COMMENT,
1479         PROPERTY_RETAIN_PREVIOUS_ARCHIVE_COUNT,
1480         PROPERTY_RETAIN_PREVIOUS_ARCHIVE_AGE));
1481  }
1482
1483
1484
1485  /**
1486   * {@inheritDoc}
1487   */
1488  @Override()
1489  @NotNull()
1490  public Map<TaskProperty,List<Object>> getTaskPropertyValues()
1491  {
1492    final Map<TaskProperty,List<Object>> props =
1493         new LinkedHashMap<>(StaticUtils.computeMapCapacity(20));
1494
1495    if (outputPath != null)
1496    {
1497      props.put(PROPERTY_OUTPUT_PATH,
1498           Collections.<Object>singletonList(outputPath));
1499    }
1500
1501    if (encryptionPassphraseFile != null)
1502    {
1503      props.put(PROPERTY_ENCRYPTION_PASSPHRASE_FILE,
1504           Collections.<Object>singletonList(encryptionPassphraseFile));
1505    }
1506
1507    if (includeExpensiveData != null)
1508    {
1509      props.put(PROPERTY_INCLUDE_EXPENSIVE_DATA,
1510           Collections.<Object>singletonList(includeExpensiveData));
1511    }
1512
1513    if (includeReplicationStateDump != null)
1514    {
1515      props.put(PROPERTY_INCLUDE_REPLICATION_STATE_DUMP,
1516           Collections.<Object>singletonList(includeReplicationStateDump));
1517    }
1518
1519    if (includeBinaryFiles != null)
1520    {
1521      props.put(PROPERTY_INCLUDE_BINARY_FILES,
1522           Collections.<Object>singletonList(includeBinaryFiles));
1523    }
1524
1525    if (includeExtensionSource != null)
1526    {
1527      props.put(PROPERTY_INCLUDE_EXTENSION_SOURCE,
1528           Collections.<Object>singletonList(includeExtensionSource));
1529    }
1530
1531    if (useSequentialMode != null)
1532    {
1533      props.put(PROPERTY_USE_SEQUENTIAL_MODE,
1534           Collections.<Object>singletonList(useSequentialMode));
1535    }
1536
1537    if (securityLevel != null)
1538    {
1539      props.put(PROPERTY_SECURITY_LEVEL,
1540           Collections.<Object>singletonList(securityLevel.getName()));
1541    }
1542
1543    if (jstackCount != null)
1544    {
1545      props.put(PROPERTY_JSTACK_COUNT,
1546           Collections.<Object>singletonList(jstackCount.longValue()));
1547    }
1548
1549    if (reportCount != null)
1550    {
1551      props.put(PROPERTY_REPORT_COUNT,
1552           Collections.<Object>singletonList(reportCount.longValue()));
1553    }
1554
1555    if (reportIntervalSeconds != null)
1556    {
1557      props.put(PROPERTY_REPORT_INTERVAL_SECONDS,
1558           Collections.<Object>singletonList(
1559                reportIntervalSeconds.longValue()));
1560    }
1561
1562    if (logDuration != null)
1563    {
1564      props.put(PROPERTY_LOG_DURATION,
1565           Collections.<Object>singletonList(logDuration));
1566    }
1567
1568    if (logFileHeadCollectionSizeKB != null)
1569    {
1570      props.put(PROPERTY_LOG_FILE_HEAD_COLLECTION_SIZE_KB,
1571           Collections.<Object>singletonList(
1572                logFileHeadCollectionSizeKB.longValue()));
1573    }
1574
1575    if (logFileTailCollectionSizeKB != null)
1576    {
1577      props.put(PROPERTY_LOG_FILE_TAIL_COLLECTION_SIZE_KB,
1578           Collections.<Object>singletonList(
1579                logFileTailCollectionSizeKB.longValue()));
1580    }
1581
1582    if (comment != null)
1583    {
1584      props.put(PROPERTY_COMMENT,
1585           Collections.<Object>singletonList(comment));
1586    }
1587
1588    if (retainPreviousSupportDataArchiveCount != null)
1589    {
1590      props.put(PROPERTY_RETAIN_PREVIOUS_ARCHIVE_COUNT,
1591           Collections.<Object>singletonList(
1592                retainPreviousSupportDataArchiveCount.longValue()));
1593    }
1594
1595    if (retainPreviousSupportDataArchiveAge != null)
1596    {
1597      props.put(PROPERTY_RETAIN_PREVIOUS_ARCHIVE_AGE,
1598           Collections.<Object>singletonList(
1599                retainPreviousSupportDataArchiveAge));
1600    }
1601
1602    props.putAll(super.getTaskPropertyValues());
1603    return Collections.unmodifiableMap(props);
1604  }
1605}