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 cause it to
067 * generate a server profile in a specified location on the server filesystem.
068 * The profile may be created in a directory structure or packaged in a zip
069 * file.
070\ * <BR>
071 * <BLOCKQUOTE>
072 *   <B>NOTE:</B>  This class, and other classes within the
073 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
074 *   supported for use against Ping Identity, UnboundID, and
075 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
076 *   for proprietary functionality or for external specifications that are not
077 *   considered stable or mature enough to be guaranteed to work in an
078 *   interoperable way with other types of LDAP servers.
079 * </BLOCKQUOTE>
080 * <BR>
081 * The properties that are available for use with this type of task include:
082 * <UL>
083 *   <LI>
084 *     The path on the server filesystem to the location in which the generated
085 *     server profile should be written.  If the profile is to be packaged into
086 *     a zip file, then this may either be the path to the zip file to create
087 *     (which must not yet exist, although its parent directory must exist) or
088 *     the path to the directory (which must already exist) in which the zip
089 *     file will be created with a server-generated name.  If the profile is
090 *     not to be packaged into a zip file, then this must be the path to the
091 *     directory in which the profile will be written, and either that
092 *     directory must exist and be empty or it must not exist but its parent
093 *     directory must exist.  In either case, the path provided may be an
094 *     absolute path, or it may be a relative path that is interpreted as
095 *     relative to the instance root.  If this property is not provided, then
096 *     the zip file or profile directory will be created in the instance root
097 *     with a server-generated name.
098 *   </LI>
099 *   <LI>
100 *     An optional set of additional paths to files or directories within the
101 *     instance root that should be included in the server profile.  These may
102 *     be specified as either absolute paths or relative paths that will be
103 *     interpreted as relative to the instance root, but the paths must refer
104 *     to files or directories that exist beneath the instance root.  If this is
105 *     omitted, then no additional include paths will be used.
106 *   </LI>
107 *   <LI>
108 *     A flag indicating whether the generated server profile should be packaged
109 *     into a zip file.  If this is omitted, then the server will determine
110 *     whether to package the profile into a zip file.
111 *   </LI>
112 *   <LI>
113 *     Optional properties indicating the number and/or age of previous profile
114 *     zip files to retain.  These options may only be used if the profile is
115 *     to be packaged into a zip file, and if the name of the zip file will be
116 *     generated by the server.
117 *   </LI>
118 * </UL>
119 */
120@NotMutable()
121@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
122public final class GenerateServerProfileTask
123       extends Task
124{
125  /**
126   * The fully-qualified name of the Java class that is used for the generate
127   * server profile task.
128   */
129  @NotNull static final String GENERATE_SERVER_PROFILE_TASK_CLASS =
130       "com.unboundid.directory.server.tasks.GenerateServerProfileTask";
131
132
133
134  /**
135   * The name of the attribute used to specify additional paths within the
136   * instance root that should be included in the generated server profile.
137   */
138  @NotNull private static final String ATTR_INCLUDE_PATH =
139       "ds-task-generate-server-profile-include-path";
140
141
142
143  /**
144   * The name of the attribute used to specify the path to which the generated
145   * profile should be written.
146   */
147  @NotNull private static final String ATTR_PROFILE_ROOT =
148       "ds-task-generate-server-profile-root";
149
150
151
152  /**
153   * The name of the attribute used to specify the age of previous profile zip
154   * files to retain.
155   */
156  @NotNull private static final String ATTR_RETAIN_AGE =
157       "ds-task-generate-server-profile-retain-age";
158
159
160
161  /**
162   * The name of the attribute used to specify the number of previous profile
163   * zip files to retain.
164   */
165  @NotNull private static final String ATTR_RETAIN_COUNT =
166       "ds-task-generate-server-profile-retain-count";
167
168
169
170  /**
171   * The name of the attribute used to indicate whether the generated server
172   * profile should be packaged into a zip file.
173   */
174  @NotNull private static final String ATTR_ZIP =
175       "ds-task-generate-server-profile-zip";
176
177
178
179  /**
180   * The name of the object class used in generate server profile task entries.
181   */
182  @NotNull private static final String OC_GENERATE_SERVER_PROFILE_TASK =
183       "ds-task-generate-server-profile";
184
185
186
187  /**
188   * The task property that will be used for the optional include paths.
189   */
190  @NotNull private static final TaskProperty PROPERTY_INCLUDE_PATH =
191       new TaskProperty(ATTR_INCLUDE_PATH,
192            INFO_GENERATE_SERVER_PROFILE_ATTR_DISPLAY_NAME_INCLUDE_PATH.get(),
193            INFO_GENERATE_SERVER_PROFILE_ATTR_DESCRIPTION_INCLUDE_PATH.get(),
194            String.class, false, true, false);
195
196
197
198  /**
199   * The task property that will be used for the profile root.
200   */
201  @NotNull private static final TaskProperty PROPERTY_PROFILE_ROOT =
202       new TaskProperty(ATTR_PROFILE_ROOT,
203            INFO_GENERATE_SERVER_PROFILE_ATTR_DISPLAY_NAME_PROFILE_ROOT.get(),
204            INFO_GENERATE_SERVER_PROFILE_ATTR_DESCRIPTION_PROFILE_ROOT.get(),
205            String.class, false, false, false);
206
207
208
209  /**
210   * The task property that will be used for the retain age.
211   */
212  @NotNull static final TaskProperty PROPERTY_RETAIN_AGE = new TaskProperty(
213       ATTR_RETAIN_AGE,
214       INFO_GENERATE_SERVER_PROFILE_ATTR_DISPLAY_NAME_RETAIN_AGE.get(),
215       INFO_GENERATE_SERVER_PROFILE_ATTR_DESCRIPTION_RETAIN_AGE.get(),
216       String.class, false, false, false);
217
218
219
220  /**
221   * The task property that will be used for the retain count.
222   */
223  @NotNull private static final TaskProperty PROPERTY_RETAIN_COUNT =
224       new TaskProperty(ATTR_RETAIN_COUNT,
225            INFO_GENERATE_SERVER_PROFILE_ATTR_DISPLAY_NAME_RETAIN_COUNT.get(),
226            INFO_GENERATE_SERVER_PROFILE_ATTR_DESCRIPTION_RETAIN_COUNT.get(),
227            Long.class, false, false, false);
228
229
230
231  /**
232   * The task property that will be used to indicate whether to package the
233   * server profile in a zip file.
234   */
235  @NotNull private static final TaskProperty PROPERTY_ZIP =
236       new TaskProperty(ATTR_ZIP,
237            INFO_GENERATE_SERVER_PROFILE_ATTR_DISPLAY_NAME_ZIP.get(),
238            INFO_GENERATE_SERVER_PROFILE_ATTR_DESCRIPTION_ZIP.get(),
239            Boolean.class, false, false, false);
240
241
242
243  /**
244   * The serial version UID for this serializable class.
245   */
246  private static final long  serialVersionUID = -6569877503912024942L;
247
248
249
250  // Indicates whether to package the generated server profile into a zip file.
251  @Nullable private final Boolean zipProfile;
252
253  // The minimum number of previous profile zip files to retain.
254  @Nullable private final Integer retainCount;
255
256  // The list of additional paths within the instance root that should be
257  // included in the generated server profile.
258  @NotNull private final List<String> includePaths;
259
260  // The path to the zip file or directory to which the generated server profile
261  // will be written.
262  @Nullable private final String profileRoot;
263
264  // The minimum age of previous profile zip files to retain.
265  @Nullable private final String retainAge;
266
267
268
269  /**
270   * Creates a new uninitialized generate server profile task instance that
271   * should only be used for obtaining general information about this task,
272   * including the task name, description, and supported properties.  Attempts
273   * to use a task created with this constructor for any other reason will
274   * likely fail.
275   */
276  public GenerateServerProfileTask()
277  {
278    super();
279
280    zipProfile = null;
281    includePaths = null;
282    profileRoot = null;
283    retainCount = null;
284    retainAge = null;
285  }
286
287
288
289  /**
290   * Creates a new generate server profile task with the provided information.
291   *
292   * @param  taskID           The task ID to use for this task.  If it is
293   *                          {@code null} then a UUID will be generated for use
294   *                          as the task ID.
295   * @param  profileRoot      The path on the server filesystem to the zip file
296   *                          or directory to which the generated server profile
297   *                          will be written.  This may be an absolute path or
298   *                          a relative path that will be interpreted as
299   *                          relative to the instance root.  If the generated
300   *                          server profile will be packaged into a zip file,
301   *                          then this must either be the path to the zip file
302   *                          to be created (which must not yet exist, although
303   *                          its parent directory must exist) or the path to
304   *                          the directory (which must already exists) in which
305   *                          the zip file is to be created.  If the server
306   *                          profile will not e zipped, then this must be the
307   *                          path to an empty or nonexistent directory in a
308   *                          parent directory that does exist.  If this is not
309   *                          provided, the server will create the zip file or
310   *                          profile directory in the instance root with a
311   *                          name that it generates.
312   * @param  includePaths     An optional list of paths to additional files or
313   *                          directories that exist within the instance root
314   *                          that should be included in the generated server
315   *                          profile.  Relative paths will be interpreted as
316   *                          relative to the instance root.  This may be
317   *                          {@code null} or empty if no additional include
318   *                          paths should be used.
319   * @param  zipProfile       Indicates whether the generated server profile
320   *                          should be packaged into a zip file.  If this is
321   *                          {@code Boolean.TRUE}, then the profile will be
322   *                          packaged into a zip file.  If this is
323   *                          {@code Boolean.FALSE}, then the profile will be
324   *                          written as a directory structure.  It may be
325   *                          {@code null} if the server should choose whether
326   *                          to package the profile into a zip file.
327   * @param  retainCount      The minimum number of preexisting server profile
328   *                          zip files to retain.  This may only be provided if
329   *                          the profile is to be packaged into a zip file and
330   *                          the profile root is specified as a directory so
331   *                          that the server will generate the zip file name.
332   *                          This may be {@code null} if only the retain age
333   *                          will be used to identify which files may be
334   *                          deleted (if a retain age is given), or if no
335   *                          preexisting profile zip files should be removed
336   *                          (if no retain age is given).
337   * @param  retainAgeMillis  The minimum age in milliseconds of preexisting
338   *                          server profile zip files to retain.  This may only
339   *                          be provided if the profile is to be packaged into
340   *                          a zip file and the profile root is specified as a
341   *                          directory so that the server will generate the zip
342   *                          file name.  This may be {@code null} if only the
343   *                          retain count will be used to identify which files
344   *                          may be deleted (if a retain count is given), or if
345   *                          no preexisting profile zip files should be removed
346   *                          (if no retain count is given).
347   */
348  public GenerateServerProfileTask(@Nullable final String taskID,
349                                   @Nullable final String profileRoot,
350                                   @Nullable final List<String> includePaths,
351                                   @Nullable final Boolean zipProfile,
352                                   @Nullable final Integer retainCount,
353                                   @Nullable final Long retainAgeMillis)
354  {
355    this(taskID, profileRoot, includePaths, zipProfile, retainCount,
356         retainAgeMillis, null, null, null, null, null, null, null, null, null,
357         null);
358  }
359
360
361
362  /**
363   * Creates a new generate server profile task with the provided information.
364   *
365   * @param  taskID                  The task ID to use for this task.  If it is
366   *                                 {@code null} then a UUID will be generated
367   *                                 for use as the task ID.
368   * @param  profileRoot             The path on the server filesystem to the
369   *                                 zip file or directory to which the
370   *                                 generated server profile will be written.
371   *                                 This may be an absolute path or a relative
372   *                                 path that will be interpreted as relative
373   *                                 to the instance root.  If the generated
374   *                                 server profile will be packaged into a zip
375   *                                 file, then this must either be the path to
376   *                                 the zip file to be created (which must not
377   *                                 yet exist, although its parent directory
378   *                                 must exist) or the path to the directory
379   *                                 (which must already exists) in which the
380   *                                 zip file is to be created.  If the server
381   *                                 profile will not e zipped, then this must
382   *                                 be the path to an empty or nonexistent
383   *                                 directory in a parent directory that does
384   *                                 exist.  If this is not provided, the server
385   *                                 will create the zip file or profile
386   *                                 directory in the instance root with a name
387   *                                 that it generates.
388   * @param  includePaths            An optional list of paths to additional
389   *                                 files or directories that exist within the
390   *                                 instance root that should be included in
391   *                                 the generated server profile.  Relative
392   *                                 paths will be interpreted as relative to
393   *                                 the instance root.  This may be
394   *                                 {@code null} or empty if no additional
395   *                                 include paths should be used.
396   * @param  zipProfile              Indicates whether the generated server
397   *                                 profile should be packaged into a zip file.
398   *                                 If this is {@code Boolean.TRUE}, then the
399   *                                 profile will be packaged into a zip file.
400   *                                 If this is {@code Boolean.FALSE}, then the
401   *                                 profile will be written as a directory
402   *                                 structure.  It may be {@code null} if the
403   *                                 server should choose whether to package the
404   *                                 profile into a zip file.
405   * @param  retainCount             The minimum number of preexisting server
406   *                                 profile zip files to retain.  This may only
407   *                                 be provided if the profile is to be
408   *                                 packaged into a zip file and the profile
409   *                                 root is specified as a directory so that
410   *                                 the server will generate the zip file name.
411   *                                 This may be {@code null} if only the retain
412   *                                 age will be used to identify which files
413   *                                 may be deleted (if a retain age is given),
414   *                                 or if no preexisting profile zip files
415   *                                 should be removed (if no retain age is
416   *                                 given).
417   * @param  retainAgeMillis         The minimum age in milliseconds of
418   *                                 preexisting server profile zip files to
419   *                                 retain.  This may only be provided if the
420   *                                 profile is to be packaged into a zip file
421   *                                 and the profile root is specified as a
422   *                                 directory so that the server will generate
423   *                                 the zip file name.  This may be
424   *                                 {@code null} if only the retain count will
425   *                                 be used to identify which files may be
426   *                                 deleted (if a retain count is given), or if
427   *                                 no preexisting profile zip files should be
428   *                                 removed (if no retain count is given).
429   * @param  scheduledStartTime      The time that this task should start
430   *                                 running.
431   * @param  dependencyIDs           The list of task IDs that will be required
432   *                                 to complete before this task will be
433   *                                 eligible to start.
434   * @param  failedDependencyAction  Indicates what action should be taken if
435   *                                 any of the dependencies for this task do
436   *                                 not complete successfully.
437   * @param  notifyOnStart           The list of e-mail addresses of individuals
438   *                                 that should be notified when this task
439   *                                 starts running.
440   * @param  notifyOnCompletion      The list of e-mail addresses of individuals
441   *                                 that should be notified when this task
442   *                                 completes.
443   * @param  notifyOnSuccess         The list of e-mail addresses of individuals
444   *                                 that should be notified if this task
445   *                                 completes successfully.
446   * @param  notifyOnError           The list of e-mail addresses of individuals
447   *                                 that should be notified if this task does
448   *                                 not complete successfully.
449   * @param  alertOnStart            Indicates whether the server should send an
450   *                                 alert notification when this task starts.
451   * @param  alertOnSuccess          Indicates whether the server should send an
452   *                                 alert notification if this task completes
453   *                                 successfully.
454   * @param  alertOnError            Indicates whether the server should send an
455   *                                 alert notification if this task fails to
456   *                                 complete successfully.
457   */
458  public GenerateServerProfileTask(@Nullable final String taskID,
459              @Nullable final String profileRoot,
460              @Nullable final List<String> includePaths,
461              @Nullable final Boolean zipProfile,
462              @Nullable final Integer retainCount,
463              @Nullable final Long retainAgeMillis,
464              @Nullable final Date scheduledStartTime,
465              @Nullable final List<String> dependencyIDs,
466              @Nullable final FailedDependencyAction failedDependencyAction,
467              @Nullable final List<String> notifyOnStart,
468              @Nullable final List<String> notifyOnCompletion,
469              @Nullable final List<String> notifyOnSuccess,
470              @Nullable final List<String> notifyOnError,
471              @Nullable final Boolean alertOnStart,
472              @Nullable final Boolean alertOnSuccess,
473              @Nullable final Boolean alertOnError)
474  {
475    super(taskID, GENERATE_SERVER_PROFILE_TASK_CLASS, scheduledStartTime,
476         dependencyIDs, failedDependencyAction, notifyOnStart,
477         notifyOnCompletion, notifyOnSuccess, notifyOnError, alertOnStart,
478         alertOnSuccess, alertOnError);
479
480    this.profileRoot = profileRoot;
481    this.zipProfile = zipProfile;
482    this.retainCount = retainCount;
483
484    if (includePaths == null)
485    {
486      this.includePaths = Collections.emptyList();
487    }
488    else
489    {
490      this.includePaths =
491           Collections.unmodifiableList(new ArrayList<>(includePaths));
492    }
493
494    if (retainAgeMillis == null)
495    {
496      retainAge = null;
497    }
498    else
499    {
500      retainAge = DurationArgument.nanosToDuration(
501           TimeUnit.MILLISECONDS.toNanos(retainAgeMillis));
502    }
503  }
504
505
506
507  /**
508   * Creates a new generate server profile task from the provided entry.
509   *
510   * @param  entry  The entry to use to create this generate server profile
511   *                task.
512   *
513   * @throws  TaskException  If the provided entry cannot be parsed as a
514   *                         generate server profile task entry.
515   */
516  public GenerateServerProfileTask(@NotNull final Entry entry)
517         throws TaskException
518  {
519    super(entry);
520
521    profileRoot = entry.getAttributeValue(ATTR_PROFILE_ROOT);
522    zipProfile = entry.getAttributeValueAsBoolean(ATTR_ZIP);
523    retainCount = entry.getAttributeValueAsInteger(ATTR_RETAIN_COUNT);
524
525    final String[] includePathValues =
526         entry.getAttributeValues(ATTR_INCLUDE_PATH);
527    if (includePathValues == null)
528    {
529      includePaths = Collections.emptyList();
530    }
531    else
532    {
533      includePaths =
534           Collections.unmodifiableList(Arrays.asList(includePathValues));
535    }
536
537    retainAge = entry.getAttributeValue(ATTR_RETAIN_AGE);
538    if (retainAge != null)
539    {
540      try
541      {
542        DurationArgument.parseDuration(retainAge, TimeUnit.MILLISECONDS);
543      }
544      catch (final ArgumentException e)
545      {
546        Debug.debugException(e);
547        throw new TaskException(
548             ERR_GENERATE_SERVER_PROFILE_ENTRY_INVALID_RETAIN_AGE.get(
549                  entry.getDN(), retainAge, e.getMessage()),
550             e);
551      }
552    }
553  }
554
555
556
557  /**
558   * Creates a generate server profile task from the provided set of task
559   * properties.
560   *
561   * @param  properties  The set of task properties and their corresponding
562   *                     values to use for the task.  It must not be
563   *                     {@code null}.
564   *
565   * @throws  TaskException  If the provided set of properties cannot be used to
566   *                         create a valid generate server profile task.
567   */
568  public GenerateServerProfileTask(
569              @NotNull final Map<TaskProperty,List<Object>> properties)
570         throws TaskException
571  {
572    super(GENERATE_SERVER_PROFILE_TASK_CLASS, properties);
573
574    Boolean zip = null;
575    Long rCount = null;
576    String profRoot = null;
577    String rAge = null;
578    final List<String> incPaths = new ArrayList<>();
579    for (final Map.Entry<TaskProperty,List<Object>> entry :
580         properties.entrySet())
581    {
582      final TaskProperty p = entry.getKey();
583      final String attrName = p.getAttributeName();
584      final List<Object> values = entry.getValue();
585
586      if (attrName.equalsIgnoreCase(ATTR_PROFILE_ROOT))
587      {
588        profRoot = parseString(p, values, null);
589      }
590      else if (attrName.equalsIgnoreCase(ATTR_INCLUDE_PATH))
591      {
592        final String[] pathArray = parseStrings(p, values, null);
593        if (pathArray != null)
594        {
595          incPaths.addAll(Arrays.asList(pathArray));
596        }
597      }
598      else if (attrName.equalsIgnoreCase(ATTR_ZIP))
599      {
600        zip = parseBoolean(p, values, null);
601      }
602      else if (attrName.equalsIgnoreCase(ATTR_RETAIN_COUNT))
603      {
604        rCount = parseLong(p, values, null);
605      }
606      else if (attrName.equalsIgnoreCase(ATTR_RETAIN_AGE))
607      {
608        rAge = parseString(p, values, null);
609        try
610        {
611          DurationArgument.parseDuration(rAge, TimeUnit.MILLISECONDS);
612        }
613        catch (final ArgumentException e)
614        {
615          Debug.debugException(e);
616          throw new TaskException(
617               ERR_GENERATE_SERVER_PROFILE_PROPS_INVALID_RETAIN_AGE.get(
618                    rAge, e.getMessage()));
619        }
620      }
621    }
622
623    profileRoot = profRoot;
624    includePaths = incPaths;
625    zipProfile = zip;
626    retainAge = rAge;
627
628    if (rCount == null)
629    {
630      retainCount = null;
631    }
632    else
633    {
634      retainCount = rCount.intValue();
635    }
636  }
637
638
639
640  /**
641   * {@inheritDoc}
642   */
643  @Override()
644  @NotNull()
645  public String getTaskName()
646  {
647    return INFO_TASK_NAME_GENERATE_SERVER_PROFILE.get();
648  }
649
650
651
652  /**
653   * {@inheritDoc}
654   */
655  @Override()
656  @NotNull()
657  public String getTaskDescription()
658  {
659    return INFO_TASK_DESCRIPTION_GENERATE_SERVER_PROFILE.get();
660  }
661
662
663
664  /**
665   * Retrieves the path on the server filesystem to the zip file or directory to
666   * which the generated server profile will be written.  It may be an absolute
667   * path or a relative path that will be interpreted as relative to the
668   * instance root.
669   *
670   * @return  The path on the server filesystem to the zip file or directory to
671   *          which the generated server profile will be written, or
672   *          {@code null} if the server will create the zip file or profile
673   *          directory in the instance root with a generated name.
674   */
675  @Nullable()
676  public String getProfileRoot()
677  {
678    return profileRoot;
679  }
680
681
682
683  /**
684   * Retrieves a list of additional paths to files or directories within the
685   * instance root that should be included in the generated server profile.
686   *
687   * @return  A list of additional paths to files or directories within the
688   *          instance root that should be included in the generated server
689   *          profile, or an empty list if no additional paths should be
690   *          included.
691   */
692  @NotNull()
693  public List<String> getIncludePaths()
694  {
695    return includePaths;
696  }
697
698
699
700  /**
701   * Retrieves a flag that indicates whether the server should package the
702   * generated server profile into a zip file.
703   *
704   * @return  {@code Boolean.TRUE} if the generated server profile should be
705   *          packaged into a zip file, {@code Boolean.FALSE} if the server
706   *          profile should be written as a directory structure, or
707   *          {@code null} if this is not specified and the server will decide
708   *          which behavior to exhibit.
709   */
710  @Nullable()
711  public Boolean getZipProfile()
712  {
713    return zipProfile;
714  }
715
716
717
718  /**
719   * Retrieves the maximum number of preexisting server profile zip files to
720   * retain after a new profile is successfully generated, if defined.
721   *
722   * @return  The maximum number of preexisting server profile zip files to
723   *          retain after a new profile is successfully generated, or
724   *          {@code null} if file retention processing should depend only on
725   *          the retain age (if defined) or if no retention processing should
726   *          be performed.
727   */
728  @Nullable()
729  public Integer getRetainCount()
730  {
731    return retainCount;
732  }
733
734
735
736  /**
737   * Retrieves the maximum age of preexisting server profile zip files to
738   * retain after a new profile is successfully generated, if defined.  The
739   * value will be formatted as a duration as used by the
740   * {@link DurationArgument} class, which is an integer followed by a time
741   * unit (millisecond, second, minute, hour, day, or week, or one of their
742   * plurals).
743   *
744   * @return  The maximum age of preexisting server profile zip files to
745   *          retain after a new profile is successfully generated, or
746   *          {@code null} if file retention processing should depend only on
747   *          the retain count (if defined) or if no retention processing should
748   *          be performed.
749   */
750  @Nullable()
751  public String getRetainAge()
752  {
753    return retainAge;
754  }
755
756
757
758  /**
759   * Retrieves the maximum age in milliseconds of preexisting server profile zip
760   * files to retain after a new profile is successfully generated, if defined.
761   *
762   * @return  The maximum age in milliseconds of preexisting server profile zip
763   *          files to retain after a new profile is successfully generated, or
764   *          {@code null} if file retention processing should depend only on
765   *          the retain count (if defined) or if no retention processing should
766   *          be performed.
767   *
768   * @throws  TaskException  If a problem is encountered while attempting to
769   *                         parse the retain age as a duration.
770   */
771  @Nullable()
772  public Long getRetainAgeMillis()
773         throws TaskException
774  {
775    if (retainAge == null)
776    {
777      return null;
778    }
779
780    try
781    {
782      return DurationArgument.parseDuration(retainAge, TimeUnit.MILLISECONDS);
783    }
784    catch (final ArgumentException e)
785    {
786      Debug.debugException(e);
787      throw new TaskException(
788           ERR_GENERATE_SERVER_PROFILE_CANNOT_PARSE_RETAIN_AGE.get(retainAge,
789                e.getMessage()),
790           e);
791    }
792  }
793
794
795
796  /**
797   * {@inheritDoc}
798   */
799  @Override()
800  @NotNull()
801  protected List<String> getAdditionalObjectClasses()
802  {
803    return Collections.singletonList(
804         OC_GENERATE_SERVER_PROFILE_TASK);
805  }
806
807
808
809  /**
810   * {@inheritDoc}
811   */
812  @Override()
813  @NotNull()
814  protected List<Attribute> getAdditionalAttributes()
815  {
816    final List<Attribute> attrList = new ArrayList<>(5);
817
818    if (profileRoot != null)
819    {
820      attrList.add(new Attribute(ATTR_PROFILE_ROOT, profileRoot));
821    }
822
823    if (! includePaths.isEmpty())
824    {
825      attrList.add(new Attribute(ATTR_INCLUDE_PATH, includePaths));
826    }
827
828    if (zipProfile != null)
829    {
830      attrList.add(new Attribute(ATTR_ZIP, zipProfile.toString()));
831    }
832
833    if (retainCount != null)
834    {
835      attrList.add(new Attribute(ATTR_RETAIN_COUNT,
836           String.valueOf(retainCount)));
837    }
838
839    if (retainAge != null)
840    {
841      attrList.add(new Attribute(ATTR_RETAIN_AGE, retainAge));
842    }
843
844    return Collections.unmodifiableList(attrList);
845  }
846
847
848
849  /**
850   * {@inheritDoc}
851   */
852  @Override()
853  @NotNull()
854  public List<TaskProperty> getTaskSpecificProperties()
855  {
856    return Collections.unmodifiableList(Arrays.asList(
857         PROPERTY_PROFILE_ROOT,
858         PROPERTY_INCLUDE_PATH,
859         PROPERTY_ZIP,
860         PROPERTY_RETAIN_COUNT,
861         PROPERTY_RETAIN_AGE));
862  }
863
864
865
866  /**
867   * {@inheritDoc}
868   */
869  @Override()
870  @NotNull()
871  public Map<TaskProperty,List<Object>> getTaskPropertyValues()
872  {
873    final LinkedHashMap<TaskProperty,List<Object>> props =
874         new LinkedHashMap<>(StaticUtils.computeMapCapacity(10));
875
876    if (profileRoot != null)
877    {
878      props.put(PROPERTY_PROFILE_ROOT,
879           Collections.<Object>singletonList(profileRoot));
880    }
881
882    if (! includePaths.isEmpty())
883    {
884      props.put(PROPERTY_INCLUDE_PATH,
885           Collections.<Object>unmodifiableList(includePaths));
886    }
887
888    if (zipProfile != null)
889    {
890      props.put(PROPERTY_ZIP,
891           Collections.<Object>singletonList(zipProfile));
892    }
893
894    if (retainCount != null)
895    {
896      props.put(PROPERTY_RETAIN_COUNT,
897           Collections.<Object>singletonList(retainCount.longValue()));
898    }
899
900    if (retainAge != null)
901    {
902      props.put(PROPERTY_RETAIN_AGE,
903           Collections.<Object>singletonList(retainAge));
904    }
905
906    props.putAll(super.getTaskPropertyValues());
907    return Collections.unmodifiableMap(props);
908  }
909}