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}