protected Action newInstance(ActionInstance actionInstance) {
   try {
     return actionInstance.getAction().newInstance();
   } catch (InstantiationException | IllegalAccessException e) {
     throw new RuntimeException(
         String.format(
             "Exception occurred while creating an action instance of type %s: %s",
             actionInstance.getAction(), e.getMessage()));
   }
 }
 @Override
 public void validate(ActionInstance actionInstance) {
   if (actionInstance == null) {
     throw new IllegalArgumentException("actionInstance cannot be null");
   }
   if (actionInstance.getName() == null || "".equals(actionInstance.getName())) {
     throw new IllegalArgumentException("name for the actionInstance cannot be null or empty");
   }
   if (actionInstance.getAction() == null) {
     throw new IllegalArgumentException("No Action class specified for the actionInstance");
   }
   if (actionInstance.getTrigger() != null) {
     actionInstance.getTrigger().validate();
   }
 }
 /**
  * Deletes/Removes the {@code ActionInstance}. If it has a {@code CronTrigger} then it is also
  * un-scheduled from scheduler
  *
  * @throws com.netflix.scheduledactions.exceptions.ActionOperationException
  */
 @Override
 public void delete(ActionInstance actionInstance) {
   actionInstanceDao.deleteActionInstance(actionInstance.getGroup(), actionInstance);
   if (actionInstance.getFenzoTrigger() != null) {
     try {
       triggerOperator.deleteTrigger(actionInstance.getGroup(), actionInstance.getFenzoTrigger());
     } catch (SchedulerException e) {
       throw new ActionOperationException(
           String.format(
               "Exception occurred while deleting trigger %s for actionInstance %s",
               actionInstance.getTrigger(), actionInstance),
           e);
     }
   }
   logger.info("Successfully deleted the actionInstance {}", actionInstance);
 }
 /**
  * Enables the {@code ActionInstance}
  *
  * @throws com.netflix.scheduledactions.exceptions.ActionOperationException
  */
 @Override
 public void enable(ActionInstance actionInstance) {
   actionInstance.setDisabled(false);
   actionInstanceDao.updateActionInstance(actionInstance);
   if (actionInstance.getFenzoTrigger() != null) {
     try {
       triggerOperator.enableTrigger(actionInstance.getFenzoTrigger());
     } catch (SchedulerException e) {
       throw new ActionOperationException(
           String.format(
               "Exception occurred while enabling trigger %s for actionInstance %s",
               actionInstance.getTrigger(), actionInstance),
           e);
     }
   }
   logger.info("Successfully enabled the actionInstance {}", actionInstance);
 }
 /** Cancels all {@code Execution}s for this {@code ActionInstance} except for the one passed */
 private void cancelPreviousExecutions(ActionInstance actionInstance, Execution execution) {
   List<Execution> executions = getInCompleteExecutionsBefore(actionInstance.getId(), execution);
   logger.info(
       "Cancelling following executions for actionInstance {} before {}: {}",
       actionInstance,
       execution,
       executions);
   for (Execution incomplete : executions) {
     cancel(incomplete, actionInstance);
   }
 }
  @Override
  public void update(ActionInstance actionInstance) {
    // Find an existing one to update
    ActionInstance existingInstance = actionInstanceDao.getActionInstance(actionInstance.getId());
    if (existingInstance == null) {
      throw new ActionOperationException(
          String.format(
              "No existing actionInstance with id %s found for the update operation",
              actionInstance.getId()));
    }
    // Set the id of the existing action instance so that this looks like an "update" operation
    actionInstance.setId(existingInstance.getId());

    // Validate the new one before deleting the existing one
    validate(actionInstance);

    // Delete the existing one
    delete(existingInstance);

    // Register the new one
    this.register(actionInstance);
    logger.info("Successfully updated the actionInstance {}", actionInstance);
  }
  /**
   * Registers a {@code ActionInstance} with actionInstance service
   *
   * @param actionInstance
   */
  @Override
  public String register(ActionInstance actionInstance) {
    validate(actionInstance);

    actionInstanceDao.createActionInstance(actionInstance.getGroup(), actionInstance);
    if (actionInstance.getTrigger() != null) {
      actionInstance.setFenzoTrigger(
          actionInstance
              .getTrigger()
              .createFenzoTrigger(actionInstance.getContext(), InternalAction.class));
      try {
        triggerOperator.registerTrigger(
            actionInstance.getGroup(), actionInstance.getFenzoTrigger());
      } catch (SchedulerException e) {
        throw new ActionOperationException(
            String.format("Exception occurred while registering actionInstance %s", actionInstance),
            e);
      }
    }
    actionInstanceDao.updateActionInstance(actionInstance);

    logger.info("Successfully registered the actionInstance {}", actionInstance);
    return actionInstance.getId();
  }
  /**
   * Executes the {@code ActionInstance}
   *
   * @throws com.netflix.scheduledactions.exceptions.ExecutionException
   */
  public Execution execute(final ActionInstance actionInstance, String initiator) {

    if (actionInstance.isDisabled()) {
      return null;
    }

    final String actionInstanceId = actionInstance.getId();
    final Execution execution = new Execution(delegateId, actionInstanceId);
    final String executionId = executionDao.createExecution(actionInstanceId, execution);

    logger.info("[{}] Created execution for actionInstance: {}", actionInstanceId, executionId);
    execution.getLogger().info(String.format("Created execution %s", executionId));

    List<Execution> previousExecutions = getInCompleteExecutionsBefore(actionInstanceId, execution);
    if (previousExecutions.size() > 0) {
      ConcurrentExecutionStrategy strategy = actionInstance.getConcurrentExecutionStrategy();
      switch (strategy) {
        case ALLOW:
          execution
              .getLogger()
              .info("Concurrent execution strategy is: ALLOW, allowing execution...");
          logger.info(
              "[{}] actionInstance concurrent execution strategy is: ALLOW, allowing execution...",
              actionInstanceId);
          break;
        case REJECT:
          Status status = Status.SKIPPED;
          status.setMessage(
              String.format(
                  "ConcurrentExecutionStrategy for ActionInstance %s is REJECT and it has incomplete executions",
                  actionInstance));
          execution.setStatus(status);
          execution.setStartTime(new Date());
          execution.setEndTime(new Date());
          logger.info(
              "[{}] actionInstance concurrent execution strategy is: REJECT, skipping execution",
              actionInstanceId);
          execution
              .getLogger()
              .info("Concurrent execution strategy is: REJECT, skipping execution");
          executionDao.updateExecution(execution);
          return execution;
        case REPLACE:
          logger.info(
              "[{}] actionInstance concurrent execution strategy is: REPLACE, cancelling previous execution(s)",
              actionInstanceId);
          cancelPreviousExecutions(actionInstance, execution);
          break;
        default:
          break;
      }
    }

    logger.info("[{}] Submitting runnable for execution: {}", actionInstanceId, executionId);

    executeService.submit(
        new Runnable() {
          @Override
          public void run() {
            try {
              Action action = newInstance(actionInstance);
              execution.getLogger().info("Calling executor.execute()...");
              logger.info(
                  "[{}] Calling executor.execute() for execution {} ...",
                  actionInstanceId,
                  executionId);
              executor.execute(action, actionInstance, execution);
            } catch (ExecutionException e) {
              Status status = e.getStatus() != null ? e.getStatus() : Status.FAILED;
              status.setMessage(e.getMessage());
              execution.setEndTime(new Date());
              execution.setStatus(status);
              execution.getLogger().error("Exception occurred while executing action", e);
            } catch (Exception e) {
              Status status = Status.FAILED;
              status.setMessage(
                  String.format(
                      "Exception occurred while executing action %s: %s",
                      actionInstance.getAction(), e.getMessage()));
              execution.getLogger().error("Exception occurred while executing action", e);
              execution.setEndTime(new Date());
              execution.setStatus(status);
            } finally {
              executionDao.updateExecution(execution);
            }
          }
        });

    return execution;
  }