mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

kenneth_suter
02.38.2007 0d1131524cfbba81cafaab90ffcda86af50c1682
Partially addressed issues 2335 and 2336 which call for support of task notifications and dependencies in client task scheduling tools.
10 files modified
416 ■■■■■ changed files
opends/src/messages/messages/tools.properties 21 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/task/FailedDependencyAction.java 28 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/task/Task.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/RestoreDB.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/ToolConstants.java 70 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/tasks/TaskClient.java 50 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/tasks/TaskScheduleInformation.java 41 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/tasks/TaskTool.java 160 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/util/StaticUtils.java 40 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/util/args/LDAPConnectionArgumentParser.java 2 ●●● patch | view | raw | blame | history
opends/src/messages/messages/tools.properties
@@ -2161,3 +2161,24 @@
INFO_DESCRIPTION_IO_ARGS_1466=Utility Input/Output Options
INFO_DESCRIPTION_LDAP_CONNECTION_ARGS_1467=LDAP Connection Options
INFO_DESCRIPTION_CONFIG_OPTIONS_ARGS_1468=Configuration Options
INFO_DESCRIPTION_TASK_COMPLETION_NOTIFICATION_1469=Specifies the email address \
  of a recipient to be notified when the task completes.  This option may be \
  specified more than once
INFO_DESCRIPTION_TASK_ERROR_NOTIFICATION_1470=Specifies the email address \
  of a recipient to be notified if an error occurs when this task executes.  \
  This option may be specified more than once
INFO_DESCRIPTION_TASK_DEPENDENCY_ID_1471=Specifies the ID of a task upon which \
  this task depends.  A task will not start execution until all its \
  dependencies have completed execution
INFO_DESCRIPTION_TASK_FAILED_DEPENDENCY_ACTION_1472=Action this task will \
  take should one if its dependent tasks fail.  The value must be one of %s.  \
  If not specified defaults to %s
SEVERE_ERR_TASKTOOL_OPTIONS_FOR_TASK_ONLY_1473=The option %s is only \
  applicable when scheduling this operation as a task
SEVERE_ERR_TASKTOOL_INVALID_EMAIL_ADDRESS_1474=The value %s for option %s is \
  not a valid email address
SEVERE_ERR_TASKTOOL_INVALID_FDA_1475=The failed dependency action value %s is \
  invalid.  The value must be one of %s
SEVERE_ERR_TASKTOOL_FDA_WITH_NO_DEPENDENCY_1476=The failed dependency action \
  option is to be used in conjunction with one or more dependencies
opends/src/server/org/opends/server/backends/task/FailedDependencyAction.java
@@ -27,7 +27,7 @@
package org.opends.server.backends.task;
import org.opends.messages.Message;
import org.opends.messages.TaskMessages;
import static org.opends.messages.TaskMessages.*;
/**
@@ -41,14 +41,14 @@
   * The action that indicates that the dependent task should be processed
   * anyway.
   */
  PROCESS(TaskMessages.INFO_FAILED_DEPENDENCY_ACTION_PROCESS.get()),
  PROCESS(INFO_FAILED_DEPENDENCY_ACTION_PROCESS.get()),
  /**
   * The action that indicates that the dependent task should be canceled.
   */
  CANCEL(TaskMessages.INFO_FAILED_DEPENDENCY_ACTION_CANCEL.get()),
  CANCEL(INFO_FAILED_DEPENDENCY_ACTION_CANCEL.get()),
@@ -56,9 +56,17 @@
   * The action that indicates that the dependent task should be disabled so
   * that an administrator will have to re-enable it before it can start.
   */
  DISABLE(TaskMessages.INFO_FAILED_DEPENDENCY_ACTION_DISABLE.get());
  DISABLE(INFO_FAILED_DEPENDENCY_ACTION_DISABLE.get());
  /**
   * Returns the default action.
   *
   * @return the default action
   */
  public static FailedDependencyAction defaultValue() {
    return CANCEL;
  }
  /**
   * Retrieves the failed dependency action that corresponds to the provided
@@ -73,15 +81,21 @@
  public static FailedDependencyAction fromString(String s)
  {
    String lowerString = s.toLowerCase();
    if (lowerString.equals("process"))
    if (lowerString.equals("process") ||
            lowerString.equals(INFO_FAILED_DEPENDENCY_ACTION_PROCESS.get().
                    toString().toLowerCase()))
    {
      return PROCESS;
    }
    else if (lowerString.equals("cancel"))
    else if (lowerString.equals("cancel") ||
            lowerString.equals(INFO_FAILED_DEPENDENCY_ACTION_CANCEL.get().
                    toString().toLowerCase()))
    {
      return CANCEL;
    }
    else if (lowerString.equals("disable"))
    else if (lowerString.equals("disable") ||
            lowerString.equals(INFO_FAILED_DEPENDENCY_ACTION_DISABLE.get().
                    toString().toLowerCase()))
    {
      return DISABLE;
    }
opends/src/server/org/opends/server/backends/task/Task.java
@@ -351,7 +351,7 @@
      failedDependencyAction = FailedDependencyAction.fromString(actionString);
      if (failedDependencyAction == null)
      {
        failedDependencyAction = FailedDependencyAction.CANCEL;
        failedDependencyAction = FailedDependencyAction.defaultValue();
      }
    }
opends/src/server/org/opends/server/tools/RestoreDB.java
@@ -265,7 +265,7 @@
    }
    if (listBackups.isPresent() && argParser.argumentsPresent()) {
    if (listBackups.isPresent() && argParser.connectionArgumentsPresent()) {
      Message message = ERR_LDAP_CONN_INCOMPATIBLE_ARGS.get(
              listBackups.getLongIdentifier());
      err.println(wrapText(message, MAX_LINE_WIDTH));
opends/src/server/org/opends/server/tools/ToolConstants.java
@@ -832,5 +832,75 @@
   * Long form of option specifying no wrapping of the command-line.
   */
  public static final String OPTION_LONG_DONT_WRAP = "dontWrap";
  /**
   * Long form of email notification upon completion option.
   */
  public static final String OPTION_LONG_COMPLETION_NOTIFICATION_EMAIL =
          "completionNotify";
  /**
   * Short form of email notification upon completion option.
   */
  public static final Character OPTION_SHORT_COMPLETION_NOTIFICATION_EMAIL =
          null;
  /**
   * Long form of email notification upon error option.
   */
  public static final String OPTION_LONG_ERROR_NOTIFICATION_EMAIL =
          "errorNotify";
  /**
   * Short form of email notification upon error option.
   */
  public static final Character OPTION_SHORT_ERROR_NOTIFICATION_EMAIL =
          null;
  /**
   * Long form of dependency option.
   */
  public static final String OPTION_LONG_DEPENDENCY = "dependency";
  /**
   * Short form of dependency option.
   */
  public static final Character OPTION_SHORT_DEPENDENCY = null;
  /**
   * Long form of failed dependency action option.
   */
  public static final String OPTION_LONG_FAILED_DEPENDENCY_ACTION =
          "failedDependencyAction";
  /**
   * Short form of failed dependency action option.
   */
  public static final Character OPTION_SHORT_FAILED_DEPENDENCY_ACTION = null;
  /**
   * Value placeholder for options taking email addresses.
   */
  public static final String OPTION_VALUE_EMAIL_ADDRESS = "{emailAddress}";
  /**
   * Value placeholder for options taking task IDs.
   */
  public static final String OPTION_VALUE_TASK_ID = "{taskId}";
  /**
   * Value placeholder for options taking actions.
   */
  public static final String OPTION_VALUE_ACTION = "{action}";
}
opends/src/server/org/opends/server/tools/tasks/TaskClient.java
@@ -59,6 +59,7 @@
import org.opends.server.types.SearchScope;
import static org.opends.server.types.ResultCode.*;
import org.opends.server.backends.task.TaskState;
import org.opends.server.backends.task.FailedDependencyAction;
import static org.opends.server.util.ServerConstants.*;
import org.opends.server.util.StaticUtils;
@@ -149,6 +150,55 @@
              startDateValues));
    }
    // add dependency IDs
    List<String> dependencyIds = information.getDependencyIds();
    if (dependencyIds != null && dependencyIds.size() > 0) {
      ArrayList<ASN1OctetString> dependencyIdValues =
              new ArrayList<ASN1OctetString>(dependencyIds.size());
      for (String dependencyId : dependencyIds) {
        dependencyIdValues.add(new ASN1OctetString(dependencyId));
      }
      attributes.add(new LDAPAttribute(ATTR_TASK_DEPENDENCY_IDS,
              dependencyIdValues));
      // add the dependency action
      FailedDependencyAction fda = information.getFailedDependencyAction();
      if (fda == null) {
        fda = FailedDependencyAction.defaultValue();
      }
      ArrayList<ASN1OctetString> fdaValues =
              new ArrayList<ASN1OctetString>(1);
      fdaValues.add(new ASN1OctetString(fda.name()));
      attributes.add(new LDAPAttribute(ATTR_TASK_FAILED_DEPENDENCY_ACTION,
              fdaValues));
    }
    // add completion notification email addresses
    List<String> compNotifEmailAddresss =
            information.getNotifyUponCompletionEmailAddresses();
    if (compNotifEmailAddresss != null && compNotifEmailAddresss.size() > 0) {
      ArrayList<ASN1OctetString> compNotifEmailAddrValues =
              new ArrayList<ASN1OctetString>(compNotifEmailAddresss.size());
      for (String emailAddr : compNotifEmailAddresss) {
        compNotifEmailAddrValues.add(new ASN1OctetString(emailAddr));
      }
      attributes.add(new LDAPAttribute(ATTR_TASK_NOTIFY_ON_COMPLETION,
              compNotifEmailAddrValues));
    }
    // add error notification email addresses
    List<String> errNotifEmailAddresss =
            information.getNotifyUponErrorEmailAddresses();
    if (errNotifEmailAddresss != null && errNotifEmailAddresss.size() > 0) {
      ArrayList<ASN1OctetString> errNotifEmailAddrValues =
              new ArrayList<ASN1OctetString>(errNotifEmailAddresss.size());
      for (String emailAddr : errNotifEmailAddresss) {
        errNotifEmailAddrValues.add(new ASN1OctetString(emailAddr));
      }
      attributes.add(new LDAPAttribute(ATTR_TASK_NOTIFY_ON_ERROR,
              errNotifEmailAddrValues));
    }
    information.addTaskAttributes(attributes);
    AddRequestProtocolOp addRequest = new AddRequestProtocolOp(entryDN,
opends/src/server/org/opends/server/tools/tasks/TaskScheduleInformation.java
@@ -28,6 +28,7 @@
package org.opends.server.tools.tasks;
import org.opends.server.types.RawAttribute;
import org.opends.server.backends.task.FailedDependencyAction;
import java.util.List;
import java.util.Date;
@@ -40,6 +41,7 @@
 */
public interface TaskScheduleInformation {
  /**
   * Adds utility specific attributes to <code>attributes</code> for
   * population of the entry that is added to the task backend.
@@ -48,6 +50,7 @@
   */
  void addTaskAttributes(List<RawAttribute> attributes);
  /**
   * Gets the objectclass used to represent scheduled instances of this
   * utility in the task backend.
@@ -56,6 +59,7 @@
   */
  String getTaskObjectclass();
  /**
   * Gets the Class that implements the utility to execute.
   *
@@ -63,10 +67,47 @@
   */
  Class getTaskClass();
  /**
   * Gets the date at which this task should be scheduled to start.
   *
   * @return date/time at which the task should be scheduled
   */
  Date getStartDateTime();
  /**
   * Gets a list of task IDs upon which this task is dependent.
   *
   * @return list of task IDs
   */
  List<String> getDependencyIds();
  /**
   * Gets the action to take should one of the dependent task fail.
   *
   * @return action to take
   */
  FailedDependencyAction getFailedDependencyAction();
  /**
   * Gets a list of email address to which an email will be sent when this
   * task completes.
   *
   * @return list of email addresses
   */
  List<String> getNotifyUponCompletionEmailAddresses();
  /**
   * Gets a list of email address to which an email will be sent if this
   * task encounters an error during execution.
   *
   * @return list of email addresses
   */
  List<String> getNotifyUponErrorEmailAddresses();
}
opends/src/server/org/opends/server/tools/tasks/TaskTool.java
@@ -43,6 +43,7 @@
import org.opends.server.types.OpenDsException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.backends.task.TaskState;
import org.opends.server.backends.task.FailedDependencyAction;
import org.opends.messages.Message;
import static org.opends.messages.ToolMessages.*;
@@ -52,6 +53,9 @@
import java.util.Set;
import java.util.HashSet;
import java.util.List;
import java.util.LinkedList;
import java.util.EnumSet;
import java.util.Collections;
import java.io.IOException;
/**
@@ -77,6 +81,21 @@
  // Argument for describing the task's start time
  StringArgument startArg;
  // Argument for specifying completion notifications
  StringArgument completionNotificationArg;
  // Argument for specifying error notifications
  StringArgument errorNotificationArg;
  // Argument for specifying dependency
  StringArgument dependencyArg;
  // Argument for specifying a failed dependency action
  StringArgument failedDependencyActionArg;
  // Client for interacting with the task backend
  TaskClient taskClient;
  /**
   * Called when this utility should perform its actions locally in this
   * JVM.
@@ -120,6 +139,42 @@
              null, null,
              INFO_DESCRIPTION_START_DATETIME.get());
      argParser.addArgument(startArg, taskGroup);
      completionNotificationArg = new StringArgument(
              OPTION_LONG_COMPLETION_NOTIFICATION_EMAIL,
              OPTION_SHORT_COMPLETION_NOTIFICATION_EMAIL,
              OPTION_LONG_COMPLETION_NOTIFICATION_EMAIL,
              false, true, true, OPTION_VALUE_EMAIL_ADDRESS,
              null, null, INFO_DESCRIPTION_TASK_COMPLETION_NOTIFICATION.get());
      argParser.addArgument(completionNotificationArg, taskGroup);
      errorNotificationArg = new StringArgument(
              OPTION_LONG_ERROR_NOTIFICATION_EMAIL,
              OPTION_SHORT_ERROR_NOTIFICATION_EMAIL,
              OPTION_LONG_ERROR_NOTIFICATION_EMAIL,
              false, true, true, OPTION_VALUE_EMAIL_ADDRESS,
              null, null, INFO_DESCRIPTION_TASK_ERROR_NOTIFICATION.get());
      argParser.addArgument(errorNotificationArg, taskGroup);
      dependencyArg = new StringArgument(
              OPTION_LONG_DEPENDENCY,
              OPTION_SHORT_DEPENDENCY,
              OPTION_LONG_DEPENDENCY,
              false, true, true, OPTION_VALUE_TASK_ID,
              null, null, INFO_DESCRIPTION_TASK_DEPENDENCY_ID.get());
      argParser.addArgument(dependencyArg, taskGroup);
      Set fdaValSet = EnumSet.allOf(FailedDependencyAction.class);
      failedDependencyActionArg = new StringArgument(
              OPTION_LONG_FAILED_DEPENDENCY_ACTION,
              OPTION_SHORT_FAILED_DEPENDENCY_ACTION,
              OPTION_LONG_FAILED_DEPENDENCY_ACTION,
              false, true, true, OPTION_VALUE_ACTION,
              null, null, INFO_DESCRIPTION_TASK_FAILED_DEPENDENCY_ACTION.get(
                StaticUtils.collectionToString(fdaValSet, ","),
                FailedDependencyAction.defaultValue().name()));
      argParser.addArgument(failedDependencyActionArg, taskGroup);
    } catch (ArgumentException e) {
      // should never happen
    }
@@ -142,6 +197,60 @@
        throw new ArgumentException(ERR_START_DATETIME_FORMAT.get());
      }
    }
    if (!processAsTask() && completionNotificationArg.isPresent()) {
      throw new ArgumentException(ERR_TASKTOOL_OPTIONS_FOR_TASK_ONLY.get(
              completionNotificationArg.getLongIdentifier()));
    }
    if (!processAsTask() && errorNotificationArg.isPresent()) {
      throw new ArgumentException(ERR_TASKTOOL_OPTIONS_FOR_TASK_ONLY.get(
              errorNotificationArg.getLongIdentifier()));
    }
    if (!processAsTask() && dependencyArg.isPresent()) {
      throw new ArgumentException(ERR_TASKTOOL_OPTIONS_FOR_TASK_ONLY.get(
              dependencyArg.getLongIdentifier()));
    }
    if (!processAsTask() && failedDependencyActionArg.isPresent()) {
      throw new ArgumentException(ERR_TASKTOOL_OPTIONS_FOR_TASK_ONLY.get(
              failedDependencyActionArg.getLongIdentifier()));
    }
    if (completionNotificationArg.isPresent()) {
      LinkedList<String> addrs = completionNotificationArg.getValues();
      for (String addr : addrs) {
        if (!StaticUtils.isEmailAddress(addr)) {
          throw new ArgumentException(ERR_TASKTOOL_INVALID_EMAIL_ADDRESS.get(
                  addr, completionNotificationArg.getLongIdentifier()));
        }
      }
    }
    if (errorNotificationArg.isPresent()) {
      LinkedList<String> addrs = errorNotificationArg.getValues();
      for (String addr : addrs) {
        if (!StaticUtils.isEmailAddress(addr)) {
          throw new ArgumentException(ERR_TASKTOOL_INVALID_EMAIL_ADDRESS.get(
                  addr, errorNotificationArg.getLongIdentifier()));
        }
      }
    }
    if (failedDependencyActionArg.isPresent()) {
      if (!dependencyArg.isPresent()) {
        throw new ArgumentException(ERR_TASKTOOL_FDA_WITH_NO_DEPENDENCY.get());
      }
      String fda = failedDependencyActionArg.getValue();
      if (null == FailedDependencyAction.fromString(fda)) {
        Set fdaValSet = EnumSet.allOf(FailedDependencyAction.class);
        throw new ArgumentException(ERR_TASKTOOL_INVALID_FDA.get(fda,
                        StaticUtils.collectionToString(fdaValSet, ",")));
      }
    }
  }
  /**
@@ -166,6 +275,51 @@
  }
  /**
   * {@inheritDoc}
   */
  public List<String> getDependencyIds() {
    if (dependencyArg.isPresent()) {
      return dependencyArg.getValues();
    } else {
      return Collections.emptyList();
    }
  }
  /**
   * {@inheritDoc}
   */
  public FailedDependencyAction getFailedDependencyAction() {
    FailedDependencyAction fda = null;
    if (failedDependencyActionArg.isPresent()) {
      String fdaString = failedDependencyActionArg.getValue();
      fda = FailedDependencyAction.fromString(fdaString);
    }
    return fda;
  }
  /**
   * {@inheritDoc}
   */
  public List<String> getNotifyUponCompletionEmailAddresses() {
    if (completionNotificationArg.isPresent()) {
      return completionNotificationArg.getValues();
    } else {
      return Collections.emptyList();
    }
  }
  /**
   * {@inheritDoc}
   */
  public List<String> getNotifyUponErrorEmailAddresses() {
    if (errorNotificationArg.isPresent()) {
      return errorNotificationArg.getValues();
    } else {
      return Collections.emptyList();
    }
  }
  /**
   * Either invokes initiates this tool's local action or schedule this
   * tool using the tasks interface based on user input.
   *
@@ -181,7 +335,7 @@
                        PrintStream out, PrintStream err) {
    int ret;
    if (argParser.argumentsPresent())
    if (processAsTask())
    {
      if (initializeServer)
      {
@@ -275,4 +429,8 @@
    return ret;
  }
  private boolean processAsTask() {
    return argParser.connectionArgumentsPresent();
  }
}
opends/src/server/org/opends/server/util/StaticUtils.java
@@ -52,6 +52,8 @@
import java.util.StringTokenizer;
import java.util.Date;
import java.util.TimeZone;
import java.util.Collection;
import java.util.Iterator;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
@@ -3321,6 +3323,29 @@
  }
  /**
   * Creates a string representation of the elements in the
   * <code>collection</code> separated by <code>separator</code>.
   *
   * @param collection to print
   * @param separator to use between elements
   *
   * @return String representing the collection
   */
  static public String collectionToString(Collection<?> collection,
                                          String separator)
  {
    StringBuilder sb = new StringBuilder();
    for (Iterator<?> iter = collection.iterator(); iter.hasNext();) {
      sb.append(iter.next());
      if (iter.hasNext()) {
        sb.append(separator);
      }
    }
    return sb.toString();
  }
  /**
   * Retrieves an array list containing the contents of the provided array.
   *
   * @param  stringArray  The string array to convert to an array list.
@@ -4036,5 +4061,20 @@
    return timeStr;
  }
  /**
   * Indicates whether or not a string represents a syntactically correct
   * email address.
   *
   * @param addr to validate
   * @return boolean where <code>true</code> indicates that the string is a
   *         syntactically correct email address
   */
  public static boolean isEmailAddress(String addr) {
    // This just does basic syntax checking.  Perhaps we
    // might want to be stricter about this.
    return addr != null && addr.contains("@") && addr.contains(".");
  }
}
opends/src/server/org/opends/server/util/args/LDAPConnectionArgumentParser.java
@@ -134,7 +134,7 @@
   * @return true if the user wants to perform a remote operation;
   *         false otherwise
   */
  public boolean argumentsPresent() {
  public boolean connectionArgumentsPresent() {
    return args != null && args.argumentsPresent();
  }