001/* 002 * Copyright 2018-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2018-2019 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.sdk.unboundidds.tasks; 022 023 024 025import java.util.Arrays; 026import java.util.Collections; 027import java.util.Date; 028import java.util.LinkedHashMap; 029import java.util.LinkedList; 030import java.util.List; 031import java.util.Map; 032 033import com.unboundid.ldap.sdk.Attribute; 034import com.unboundid.ldap.sdk.Entry; 035import com.unboundid.util.NotMutable; 036import com.unboundid.util.StaticUtils; 037import com.unboundid.util.ThreadSafety; 038import com.unboundid.util.ThreadSafetyLevel; 039 040import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*; 041 042 043 044/** 045 * This class defines a Directory Server task that can be used to cause the 046 * server to execute a specified command with a given set of arguments. 047 * <BR> 048 * <BLOCKQUOTE> 049 * <B>NOTE:</B> This class, and other classes within the 050 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 051 * supported for use against Ping Identity, UnboundID, and 052 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 053 * for proprietary functionality or for external specifications that are not 054 * considered stable or mature enough to be guaranteed to work in an 055 * interoperable way with other types of LDAP servers. 056 * </BLOCKQUOTE> 057 * <BR> 058 * The server imposes limitation on the commands that can be executed and on the 059 * circumstances in which they can be invoked. See the 060 * exec-command-whitelist.txt file in the server's config directory for a 061 * summary of these restrictions, and for additional information about exec 062 * tasks. 063 * <BR><BR> 064 * The properties that are available for use with this type of task include: 065 * <UL> 066 * <LI>The absolute path to the command to execute. This must be 067 * provided.</LI> 068 * <LI>An optional string with arguments to provide to the command.</LI> 069 * <LI>An optional path to a file to which the command's output should be 070 * written.</LI> 071 * <LI>An optional boolean flag that indicates whether to log the command's 072 * output to the server error log.</LI> 073 * <LI>An optional string that specifies the task state that should be used 074 * if the command completes with a nonzero exit code.</LI> 075 * </UL> 076 */ 077@NotMutable() 078@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 079public final class ExecTask 080 extends Task 081{ 082 /** 083 * The fully-qualified name of the Java class that is used for the exec task. 084 */ 085 static final String EXEC_TASK_CLASS = 086 "com.unboundid.directory.server.tasks.ExecTask"; 087 088 089 090 /** 091 * The name of the attribute used to specify the absolute path for the command 092 * to be executed. 093 */ 094 private static final String ATTR_COMMAND_PATH = "ds-task-exec-command-path"; 095 096 097 098 /** 099 * The name of the attribute used to specify the argument string to provide 100 * when running the command. 101 */ 102 private static final String ATTR_COMMAND_ARGUMENTS = 103 "ds-task-exec-command-arguments"; 104 105 106 107 /** 108 * The name of the attribute used to specify the path to a file in which the 109 * command's output should be recorded. 110 */ 111 private static final String ATTR_COMMAND_OUTPUT_FILE = 112 "ds-task-exec-command-output-file"; 113 114 115 116 /** 117 * The name of the attribute used to indicate whether to record the command's 118 * output in the server error log. 119 */ 120 private static final String ATTR_LOG_COMMAND_OUTPUT = 121 "ds-task-exec-log-command-output"; 122 123 124 125 /** 126 * The name of the attribute used to specify the task state for commands that 127 * complete with a nonzero exit code. 128 */ 129 private static final String ATTR_TASK_STATE_FOR_NONZERO_EXIT_CODE = 130 "ds-task-exec-task-completion-state-for-nonzero-exit-code"; 131 132 133 134 /** 135 * The name of the object class used in EXEC task entries. 136 */ 137 private static final String OC_EXEC_TASK = "ds-task-exec"; 138 139 140 141 /** 142 * The task property that will be used for the command path. 143 */ 144 private static final TaskProperty PROPERTY_COMMAND_PATH = 145 new TaskProperty(ATTR_COMMAND_PATH, 146 INFO_EXEC_DISPLAY_NAME_COMMAND_PATH.get(), 147 INFO_EXEC_DESCRIPTION_COMMAND_PATH.get(), String.class, true, false, 148 false); 149 150 151 152 /** 153 * The task property that will be used for the command arguments. 154 */ 155 private static final TaskProperty PROPERTY_COMMAND_ARGUMENTS = 156 new TaskProperty(ATTR_COMMAND_ARGUMENTS, 157 INFO_EXEC_DISPLAY_NAME_COMMAND_ARGUMENTS.get(), 158 INFO_EXEC_DESCRIPTION_COMMAND_ARGUMENTS.get(), String.class, false, 159 false, false); 160 161 162 163 /** 164 * The task property that will be used for the command output file. 165 */ 166 private static final TaskProperty PROPERTY_COMMAND_OUTPUT_FILE = 167 new TaskProperty(ATTR_COMMAND_OUTPUT_FILE, 168 INFO_EXEC_DISPLAY_NAME_COMMAND_OUTPUT_FILE.get(), 169 INFO_EXEC_DESCRIPTION_COMMAND_OUTPUT_FILE.get(), String.class, false, 170 false, false); 171 172 173 174 /** 175 * The task property that will be used for the log command output flag. 176 */ 177 private static final TaskProperty PROPERTY_LOG_COMMAND_OUTPUT = 178 new TaskProperty(ATTR_LOG_COMMAND_OUTPUT, 179 INFO_EXEC_DISPLAY_NAME_LOG_COMMAND_OUTPUT.get(), 180 INFO_EXEC_DESCRIPTION_LOG_COMMAND_OUTPUT.get(), Boolean.class, false, 181 false, false); 182 183 184 185 /** 186 * The task property that will be used for the task state for commands that 187 * complete with a nonzero exit code. 188 */ 189 private static final TaskProperty PROPERTY_TASK_STATE_FOR_NONZERO_EXIT_CODE = 190 new TaskProperty(ATTR_TASK_STATE_FOR_NONZERO_EXIT_CODE, 191 INFO_EXEC_DISPLAY_NAME_TASK_STATE_FOR_NONZERO_EXIT_CODE.get(), 192 INFO_EXEC_DESCRIPTION_NAME_TASK_STATE_FOR_NONZERO_EXIT_CODE.get(), 193 String.class, false, false, false, 194 new String[] 195 { 196 "STOPPED_BY_ERROR", 197 "STOPPED-BY-ERROR", 198 "COMPLETED_WITH_ERRORS", 199 "COMPLETED-WITH-ERRORS", 200 "COMPLETED_SUCCESSFULLY", 201 "COMPLETED-SUCCESSFULLY" 202 }); 203 204 205 206 /** 207 * The serial version UID for this serializable class. 208 */ 209 private static final long serialVersionUID = -6541429978844959603L; 210 211 212 213 // Indicates whether command output is to be logged. 214 private final Boolean logCommandOutput; 215 216 // The arguments to provide when executing the command. 217 private final String commandArguments; 218 219 // The path to the file to which command output should be written. 220 private final String commandOutputFile; 221 222 // The path to the command to be executed. 223 private final String commandPath; 224 225 // The name of the task state that should be used if the command completes 226 // with a nonzero exit code. 227 private final String taskStateForNonZeroExitCode; 228 229 230 231 /** 232 * Creates a new, uninitialized exec task instance that should only be used 233 * for obtaining general information about this task, including the task name, 234 * description, and supported properties. Attempts to use a task created with 235 * this constructor for any other reason will likely fail. 236 */ 237 public ExecTask() 238 { 239 commandPath = null; 240 commandArguments = null; 241 commandOutputFile = null; 242 logCommandOutput = null; 243 taskStateForNonZeroExitCode = null; 244 } 245 246 247 248 /** 249 * Creates a new exec task with the provided information. 250 * 251 * @param commandPath 252 * The absolute path (on the server filesystem) to the command 253 * that should be executed. This must not be {@code null}. 254 * @param commandArguments 255 * The complete set of arguments that should be used when 256 * running the command. This may be {@code null} if no arguments 257 * should be provided. 258 * @param commandOutputFile 259 * The path to an output file that should be used to record all 260 * output that the command writes to standard output or standard 261 * error. This may be {@code null} if the command output should 262 * not be recorded in a file. 263 * @param logCommandOutput 264 * Indicates whether to record the command output in the server 265 * error log. If this is {@code true}, then all non-blank lines 266 * that the command writes to standard output or standard error 267 * will be recorded in the server error log. if this is 268 * {@code false}, then the output will not be recorded in the 269 * server error log. If this is {@code null}, then the server 270 * will determine whether to log command output. Note that a 271 * value of {@code true} should only be used if you are certain 272 * that the tool will only generate text-based output, and you 273 * should use {@code false} if you know that the command may 274 * generate non-text output. 275 * @param taskStateForNonZeroExitCode 276 * The task state that should be used if the command completes 277 * with a nonzero exit code. This may be {@code null} to 278 * indicate that the server should determine the appropriate task 279 * state. If it is non-{@code null}, then the value must be one 280 * of {@link TaskState#STOPPED_BY_ERROR}, 281 * {@link TaskState#COMPLETED_WITH_ERRORS}, or 282 * {@link TaskState#COMPLETED_SUCCESSFULLY}. 283 * 284 * @throws TaskException If there is a problem with any of the provided 285 * arguments. 286 */ 287 public ExecTask(final String commandPath, final String commandArguments, 288 final String commandOutputFile, 289 final Boolean logCommandOutput, 290 final TaskState taskStateForNonZeroExitCode) 291 throws TaskException 292 { 293 this(null, commandPath, commandArguments, commandOutputFile, 294 logCommandOutput, taskStateForNonZeroExitCode, null, null, null, null, 295 null); 296 } 297 298 299 300 /** 301 * Creates a new exec task with the provided information. 302 * 303 * @param taskID 304 * The task ID to use for this task. If it is {@code null} then 305 * a UUID will be generated for use as the task ID. 306 * @param commandPath 307 * The absolute path (on the server filesystem) to the command 308 * that should be executed. This must not be {@code null}. 309 * @param commandArguments 310 * The complete set of arguments that should be used when 311 * running the command. This may be {@code null} if no arguments 312 * should be provided. 313 * @param commandOutputFile 314 * The path to an output file that should be used to record all 315 * output that the command writes to standard output or standard 316 * error. This may be {@code null} if the command output should 317 * not be recorded in a file. 318 * @param logCommandOutput 319 * Indicates whether to record the command output in the server 320 * error log. If this is {@code true}, then all non-blank lines 321 * that the command writes to standard output or standard error 322 * will be recorded in the server error log. if this is 323 * {@code false}, then the output will not be recorded in the 324 * server error log. If this is {@code null}, then the server 325 * will determine whether to log command output. Note that a 326 * value of {@code true} should only be used if you are certain 327 * that the tool will only generate text-based output, and you 328 * should use {@code false} if you know that the command may 329 * generate non-text output. 330 * @param taskStateForNonZeroExitCode 331 * The task state that should be used if the command completes 332 * with a nonzero exit code. This may be {@code null} to 333 * indicate that the server should determine the appropriate task 334 * state. If it is non-{@code null}, then the value must be one 335 * of {@link TaskState#STOPPED_BY_ERROR}, 336 * {@link TaskState#COMPLETED_WITH_ERRORS}, or 337 * {@link TaskState#COMPLETED_SUCCESSFULLY}. 338 * @param scheduledStartTime 339 * The time that this task should start running. 340 * @param dependencyIDs 341 * The list of task IDs that will be required to complete before 342 * this task will be eligible to start. 343 * @param failedDependencyAction 344 * Indicates what action should be taken if any of the 345 * dependencies for this task do not complete successfully. 346 * @param notifyOnCompletion 347 * The list of e-mail addresses of individuals that should be 348 * notified when this task completes. 349 * @param notifyOnError 350 * The list of e-mail addresses of individuals that should be 351 * notified if this task does not complete successfully. 352 * 353 * @throws TaskException If there is a problem with any of the provided 354 * arguments. 355 */ 356 public ExecTask(final String taskID, final String commandPath, 357 final String commandArguments, final String commandOutputFile, 358 final Boolean logCommandOutput, 359 final TaskState taskStateForNonZeroExitCode, 360 final Date scheduledStartTime, 361 final List<String> dependencyIDs, 362 final FailedDependencyAction failedDependencyAction, 363 final List<String> notifyOnCompletion, 364 final List<String> notifyOnError) 365 throws TaskException 366 { 367 this(taskID, commandPath, commandArguments, commandOutputFile, 368 logCommandOutput, taskStateForNonZeroExitCode, scheduledStartTime, 369 dependencyIDs, failedDependencyAction, null, notifyOnCompletion, 370 null, notifyOnError, null, null, null); 371 } 372 373 374 375 /** 376 * Creates a new exec task with the provided information. 377 * 378 * @param taskID 379 * The task ID to use for this task. If it is {@code null} then 380 * a UUID will be generated for use as the task ID. 381 * @param commandPath 382 * The absolute path (on the server filesystem) to the command 383 * that should be executed. This must not be {@code null}. 384 * @param commandArguments 385 * The complete set of arguments that should be used when 386 * running the command. This may be {@code null} if no arguments 387 * should be provided. 388 * @param commandOutputFile 389 * The path to an output file that should be used to record all 390 * output that the command writes to standard output or standard 391 * error. This may be {@code null} if the command output should 392 * not be recorded in a file. 393 * @param logCommandOutput 394 * Indicates whether to record the command output in the server 395 * error log. If this is {@code true}, then all non-blank lines 396 * that the command writes to standard output or standard error 397 * will be recorded in the server error log. if this is 398 * {@code false}, then the output will not be recorded in the 399 * server error log. If this is {@code null}, then the server 400 * will determine whether to log command output. Note that a 401 * value of {@code true} should only be used if you are certain 402 * that the tool will only generate text-based output, and you 403 * should use {@code false} if you know that the command may 404 * generate non-text output. 405 * @param taskStateForNonZeroExitCode 406 * The task state that should be used if the command completes 407 * with a nonzero exit code. This may be {@code null} to 408 * indicate that the server should determine the appropriate task 409 * state. If it is non-{@code null}, then the value must be one 410 * of {@link TaskState#STOPPED_BY_ERROR}, 411 * {@link TaskState#COMPLETED_WITH_ERRORS}, or 412 * {@link TaskState#COMPLETED_SUCCESSFULLY}. 413 * @param scheduledStartTime 414 * The time that this task should start running. 415 * @param dependencyIDs 416 * The list of task IDs that will be required to complete before 417 * this task will be eligible to start. 418 * @param failedDependencyAction 419 * Indicates what action should be taken if any of the 420 * dependencies for this task do not complete successfully. 421 * @param notifyOnStart 422 * The list of e-mail addresses of individuals that should be 423 * notified when this task starts. 424 * @param notifyOnCompletion 425 * The list of e-mail addresses of individuals that should be 426 * notified when this task completes. 427 * @param notifyOnSuccess 428 * The list of e-mail addresses of individuals that should be 429 * notified if this task completes successfully. 430 * @param notifyOnError 431 * The list of e-mail addresses of individuals that should be 432 * notified if this task does not complete successfully. 433 * @param alertOnStart 434 * Indicates whether the server should send an alert notification 435 * when this task starts. 436 * @param alertOnSuccess 437 * Indicates whether the server should send an alert notification 438 * if this task completes successfully. 439 * @param alertOnError 440 * Indicates whether the server should send an alert notification 441 * if this task fails to complete successfully. 442 * 443 * @throws TaskException If there is a problem with any of the provided 444 * arguments. 445 */ 446 public ExecTask(final String taskID, final String commandPath, 447 final String commandArguments, final String commandOutputFile, 448 final Boolean logCommandOutput, 449 final TaskState taskStateForNonZeroExitCode, 450 final Date scheduledStartTime, 451 final List<String> dependencyIDs, 452 final FailedDependencyAction failedDependencyAction, 453 final List<String> notifyOnStart, 454 final List<String> notifyOnCompletion, 455 final List<String> notifyOnSuccess, 456 final List<String> notifyOnError, final Boolean alertOnStart, 457 final Boolean alertOnSuccess, final Boolean alertOnError) 458 throws TaskException 459 { 460 super(taskID, EXEC_TASK_CLASS, scheduledStartTime, dependencyIDs, 461 failedDependencyAction, notifyOnStart, notifyOnCompletion, 462 notifyOnSuccess, notifyOnError, alertOnStart, alertOnSuccess, 463 alertOnError); 464 465 this.commandPath = commandPath; 466 this.commandArguments = commandArguments; 467 this.commandOutputFile = commandOutputFile; 468 this.logCommandOutput = logCommandOutput; 469 470 if ((commandPath == null) || commandPath.isEmpty()) 471 { 472 throw new TaskException(ERR_EXEC_MISSING_PATH.get()); 473 } 474 475 if (taskStateForNonZeroExitCode == null) 476 { 477 this.taskStateForNonZeroExitCode = null; 478 } 479 else 480 { 481 switch (taskStateForNonZeroExitCode) 482 { 483 case STOPPED_BY_ERROR: 484 case COMPLETED_WITH_ERRORS: 485 case COMPLETED_SUCCESSFULLY: 486 this.taskStateForNonZeroExitCode = taskStateForNonZeroExitCode.name(); 487 break; 488 default: 489 throw new TaskException( 490 ERR_EXEC_INVALID_STATE_FOR_NONZERO_EXIT_CODE.get( 491 TaskState.STOPPED_BY_ERROR.name(), 492 TaskState.COMPLETED_WITH_ERRORS.name(), 493 TaskState.COMPLETED_SUCCESSFULLY.name())); 494 } 495 } 496 } 497 498 499 500 /** 501 * Creates a new exec task from the provided entry. 502 * 503 * @param entry The entry to use to create this exec task. 504 * 505 * @throws TaskException If the provided entry cannot be parsed as an exec 506 * task entry. 507 */ 508 public ExecTask(final Entry entry) 509 throws TaskException 510 { 511 super(entry); 512 513 514 // Get the command to execute. It must be provided. 515 commandPath = entry.getAttributeValue(ATTR_COMMAND_PATH); 516 if (commandPath == null) 517 { 518 throw new TaskException(ERR_EXEC_ENTRY_MISSING_COMMAND_PATH.get( 519 entry.getDN(), ATTR_COMMAND_PATH)); 520 } 521 522 commandArguments = entry.getAttributeValue(ATTR_COMMAND_ARGUMENTS); 523 commandOutputFile = entry.getAttributeValue(ATTR_COMMAND_OUTPUT_FILE); 524 logCommandOutput = 525 entry.getAttributeValueAsBoolean(ATTR_LOG_COMMAND_OUTPUT); 526 taskStateForNonZeroExitCode = 527 entry.getAttributeValue(ATTR_TASK_STATE_FOR_NONZERO_EXIT_CODE); 528 } 529 530 531 532 /** 533 * Creates a new exec task from the provided set of task properties. 534 * 535 * @param properties The set of task properties and their corresponding 536 * values to use for the task. It must not be 537 * {@code null}. 538 * 539 * @throws TaskException If the provided set of properties cannot be used to 540 * create a valid exec task. 541 */ 542 public ExecTask(final Map<TaskProperty,List<Object>> properties) 543 throws TaskException 544 { 545 super(EXEC_TASK_CLASS, properties); 546 547 String path = null; 548 String arguments = null; 549 String outputFile = null; 550 Boolean logOutput = null; 551 String nonZeroExitState = null; 552 for (final Map.Entry<TaskProperty,List<Object>> entry : 553 properties.entrySet()) 554 { 555 final TaskProperty p = entry.getKey(); 556 final String attrName = StaticUtils.toLowerCase(p.getAttributeName()); 557 final List<Object> values = entry.getValue(); 558 559 if (attrName.equals(ATTR_COMMAND_PATH)) 560 { 561 path = parseString(p, values, path); 562 } 563 else if (attrName.equals(ATTR_COMMAND_ARGUMENTS)) 564 { 565 arguments = parseString(p, values, arguments); 566 } 567 else if (attrName.equals(ATTR_COMMAND_OUTPUT_FILE)) 568 { 569 outputFile = parseString(p, values, outputFile); 570 } 571 else if (attrName.equals(ATTR_LOG_COMMAND_OUTPUT)) 572 { 573 logOutput = parseBoolean(p, values, logOutput); 574 } 575 else if (attrName.equals(ATTR_TASK_STATE_FOR_NONZERO_EXIT_CODE)) 576 { 577 nonZeroExitState = parseString(p, values, nonZeroExitState); 578 } 579 } 580 581 commandPath = path; 582 commandArguments = arguments; 583 commandOutputFile = outputFile; 584 logCommandOutput = logOutput; 585 taskStateForNonZeroExitCode = nonZeroExitState; 586 587 if (commandPath == null) 588 { 589 throw new TaskException(ERR_EXEC_PROPERTIES_MISSING_COMMAND_PATH.get()); 590 } 591 } 592 593 594 595 /** 596 * {@inheritDoc} 597 */ 598 @Override() 599 public String getTaskName() 600 { 601 return INFO_TASK_NAME_EXEC.get(); 602 } 603 604 605 606 /** 607 * {@inheritDoc} 608 */ 609 @Override() 610 public String getTaskDescription() 611 { 612 return INFO_TASK_DESCRIPTION_EXEC.get(); 613 } 614 615 616 617 /** 618 * Retrieves the path to the command to be executed. 619 * 620 * @return The path to the command to be executed. 621 */ 622 public String getCommandPath() 623 { 624 return commandPath; 625 } 626 627 628 629 /** 630 * Retrieves a string with the values of the arguments that should be provided 631 * when running the command. 632 * 633 * @return A string with the values of the arguments that should be provided 634 * when running the command, or {@code null} if the command should be 635 * run without any arguments. 636 */ 637 public String getCommandArguments() 638 { 639 return commandArguments; 640 } 641 642 643 644 /** 645 * Retrieves the path to a file to which the command's output should be 646 * written. 647 * 648 * @return The path to a file to which the command's output should be 649 * written, or {@code null} if the output should not be written to a 650 * file. 651 */ 652 public String getCommandOutputFile() 653 { 654 return commandOutputFile; 655 } 656 657 658 659 /** 660 * Indicates whether the command's output should be recorded in the server's 661 * error log. 662 * 663 * @return {@code true} if the command's output should be recorded in the 664 * server's error log, {@code false} if the output should not be 665 * logged, or {@code null} if the task should not specify the 666 * behavior. 667 */ 668 public Boolean logCommandOutput() 669 { 670 return logCommandOutput; 671 } 672 673 674 675 /** 676 * Retrieves a string representation of the task state that should be returned 677 * if the command completes with a nonzero exit code. 678 * 679 * @return A string representation of the task state that should be returned 680 * if the command completes with a nonzero exit state, or 681 * {@code null} if the task should not specify the return state. 682 */ 683 public String getTaskStateForNonZeroExitCode() 684 { 685 return taskStateForNonZeroExitCode; 686 } 687 688 689 690 /** 691 * {@inheritDoc} 692 */ 693 @Override() 694 protected List<String> getAdditionalObjectClasses() 695 { 696 return Collections.singletonList(OC_EXEC_TASK); 697 } 698 699 700 701 /** 702 * {@inheritDoc} 703 */ 704 @Override() 705 protected List<Attribute> getAdditionalAttributes() 706 { 707 final LinkedList<Attribute> attrList = new LinkedList<>(); 708 attrList.add(new Attribute(ATTR_COMMAND_PATH, commandPath)); 709 710 if (commandArguments != null) 711 { 712 attrList.add(new Attribute(ATTR_COMMAND_ARGUMENTS, commandArguments)); 713 } 714 715 if (commandOutputFile != null) 716 { 717 attrList.add(new Attribute(ATTR_COMMAND_OUTPUT_FILE, commandOutputFile)); 718 } 719 720 if (logCommandOutput != null) 721 { 722 attrList.add(new Attribute(ATTR_LOG_COMMAND_OUTPUT, 723 String.valueOf(logCommandOutput))); 724 } 725 726 if (taskStateForNonZeroExitCode != null) 727 { 728 attrList.add(new Attribute(ATTR_TASK_STATE_FOR_NONZERO_EXIT_CODE, 729 taskStateForNonZeroExitCode)); 730 } 731 732 return attrList; 733 } 734 735 736 737 /** 738 * {@inheritDoc} 739 */ 740 @Override() 741 public List<TaskProperty> getTaskSpecificProperties() 742 { 743 return Collections.unmodifiableList(Arrays.asList( 744 PROPERTY_COMMAND_PATH, PROPERTY_COMMAND_ARGUMENTS, 745 PROPERTY_COMMAND_OUTPUT_FILE, PROPERTY_LOG_COMMAND_OUTPUT, 746 PROPERTY_TASK_STATE_FOR_NONZERO_EXIT_CODE)); 747 } 748 749 750 751 /** 752 * {@inheritDoc} 753 */ 754 @Override() 755 public Map<TaskProperty,List<Object>> getTaskPropertyValues() 756 { 757 final LinkedHashMap<TaskProperty, List<Object>> props = 758 new LinkedHashMap<>(StaticUtils.computeMapCapacity(5)); 759 760 props.put(PROPERTY_COMMAND_PATH, 761 Collections.<Object>singletonList(commandPath)); 762 763 if (commandArguments != null) 764 { 765 props.put(PROPERTY_COMMAND_ARGUMENTS, 766 Collections.<Object>singletonList(commandArguments)); 767 } 768 769 if (commandOutputFile != null) 770 { 771 props.put(PROPERTY_COMMAND_OUTPUT_FILE, 772 Collections.<Object>singletonList(commandOutputFile)); 773 } 774 775 if (logCommandOutput != null) 776 { 777 props.put(PROPERTY_LOG_COMMAND_OUTPUT, 778 Collections.<Object>singletonList(logCommandOutput)); 779 } 780 781 if (taskStateForNonZeroExitCode != null) 782 { 783 props.put(PROPERTY_TASK_STATE_FOR_NONZERO_EXIT_CODE, 784 Collections.<Object>singletonList(taskStateForNonZeroExitCode)); 785 } 786 787 return Collections.unmodifiableMap(props); 788 } 789}