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