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