All Downloads are FREE. Search and download functionalities are using the official Maven repository.

azkaban.trigger.Trigger Maven / Gradle / Ivy

/*
 * Copyright 2012 LinkedIn Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package azkaban.trigger;

import static java.util.Objects.requireNonNull;

import azkaban.utils.JSONUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.joda.time.DateTime;


public class Trigger {

  private static final Logger logger = Logger.getLogger(Trigger.class);
  private static ActionTypeLoader actionTypeLoader;
  private final long submitTime;
  private final String submitUser;
  private final String source;
  private final List actions;
  private final List expireActions;
  private Condition expireCondition;
  private Condition triggerCondition;
  private int triggerId = -1;
  private long lastModifyTime;
  private TriggerStatus status = TriggerStatus.READY;
  private Map info = new HashMap<>();
  private Map context = new HashMap<>();
  private boolean resetOnTrigger = true;
  private boolean resetOnExpire = true;

  private long nextCheckTime = -1;

  private Trigger() throws TriggerManagerException {
    throw new TriggerManagerException("Triggers should always be specified");
  }

  private Trigger(final int triggerId, final long lastModifyTime, final long submitTime,
      final String submitUser, final String source, final Condition triggerCondition,
      final Condition expireCondition, final List actions,
      final List expireActions, final Map info,
      final Map context) {
    requireNonNull(submitUser);
    requireNonNull(source);
    requireNonNull(triggerCondition);
    requireNonNull(expireActions);
    requireNonNull(info);
    requireNonNull(context);

    this.lastModifyTime = lastModifyTime;
    this.submitTime = submitTime;
    this.submitUser = submitUser;
    this.source = source;
    this.triggerCondition = triggerCondition;
    this.expireCondition = expireCondition;
    this.actions = actions;
    this.triggerId = triggerId;
    this.expireActions = expireActions;
    this.info = info;
    this.context = context;
  }

  public static ActionTypeLoader getActionTypeLoader() {
    return actionTypeLoader;
  }

  public static synchronized void setActionTypeLoader(final ActionTypeLoader loader) {
    Trigger.actionTypeLoader = loader;
  }

  public static Trigger fromJson(final Object obj) throws Exception {

    if (actionTypeLoader == null) {
      throw new Exception("Trigger Action Type loader not initialized.");
    }
    final Map jsonObj = (HashMap) obj;

    Trigger trigger = null;
    try {
      logger.info("Decoding for " + JSONUtils.toJSON(obj));
      final Condition triggerCond = Condition.fromJson(jsonObj.get("triggerCondition"));
      final Condition expireCond = Condition.fromJson(jsonObj.get("expireCondition"));
      final List actions = new ArrayList<>();
      final List actionsJson = (List) jsonObj.get("actions");
      for (final Object actObj : actionsJson) {
        final Map oneActionJson = (HashMap) actObj;
        final String type = (String) oneActionJson.get("type");
        final TriggerAction act =
            actionTypeLoader.createActionFromJson(type,
                oneActionJson.get("actionJson"));
        actions.add(act);
      }
      final List expireActions = new ArrayList<>();
      final List expireActionsJson =
          (List) jsonObj.get("expireActions");
      for (final Object expireActObj : expireActionsJson) {
        final Map oneExpireActionJson =
            (HashMap) expireActObj;
        final String type = (String) oneExpireActionJson.get("type");
        final TriggerAction expireAct =
            actionTypeLoader.createActionFromJson(type,
                oneExpireActionJson.get("actionJson"));
        expireActions.add(expireAct);
      }
      final boolean resetOnTrigger =
          Boolean.valueOf((String) jsonObj.get("resetOnTrigger"));
      final boolean resetOnExpire =
          Boolean.valueOf((String) jsonObj.get("resetOnExpire"));
      final String submitUser = (String) jsonObj.get("submitUser");
      final String source = (String) jsonObj.get("source");
      final long submitTime = Long.valueOf((String) jsonObj.get("submitTime"));
      final long lastModifyTime =
          Long.valueOf((String) jsonObj.get("lastModifyTime"));
      final int triggerId = Integer.valueOf((String) jsonObj.get("triggerId"));
      final TriggerStatus status =
          TriggerStatus.valueOf((String) jsonObj.get("status"));
      final Map info = (Map) jsonObj.get("info");
      Map context =
          (Map) jsonObj.get("context");
      if (context == null) {
        context = new HashMap<>();
      }
      for (final ConditionChecker checker : triggerCond.getCheckers().values()) {
        checker.setContext(context);
      }
      for (final ConditionChecker checker : expireCond.getCheckers().values()) {
        checker.setContext(context);
      }
      for (final TriggerAction action : actions) {
        action.setContext(context);
      }
      for (final TriggerAction action : expireActions) {
        action.setContext(context);
      }

      trigger = new Trigger.TriggerBuilder(submitUser,
          source,
          triggerCond,
          expireCond,
          actions)
          .setId(triggerId)
          .setLastModifyTime(lastModifyTime)
          .setSubmitTime(submitTime)
          .setExpireActions(expireActions)
          .setInfo(info)
          .setContext(context)
          .build();

      trigger.setResetOnExpire(resetOnExpire);
      trigger.setResetOnTrigger(resetOnTrigger);
      trigger.setStatus(status);
    } catch (final Exception e) {
      e.printStackTrace();
      logger.error("Failed to decode the trigger.", e);
      throw new Exception("Failed to decode the trigger.", e);
    }

    return trigger;
  }

  public void updateNextCheckTime() {
    this.nextCheckTime = Math.min(this.triggerCondition.getNextCheckTime(),
        this.expireCondition.getNextCheckTime());
  }

  public long getNextCheckTime() {
    return this.nextCheckTime;
  }

  public void setNextCheckTime(final long nct) {
    this.nextCheckTime = nct;
  }

  public long getSubmitTime() {
    return this.submitTime;
  }

  public String getSubmitUser() {
    return this.submitUser;
  }

  public TriggerStatus getStatus() {
    return this.status;
  }

  public void setStatus(final TriggerStatus status) {
    this.status = status;
  }

  public Condition getTriggerCondition() {
    return this.triggerCondition;
  }

  public void setTriggerCondition(final Condition triggerCondition) {
    this.triggerCondition = triggerCondition;
  }

  public Condition getExpireCondition() {
    return this.expireCondition;
  }

  public void setExpireCondition(final Condition expireCondition) {
    this.expireCondition = expireCondition;
  }

  public List getActions() {
    return this.actions;
  }

  public List getExpireActions() {
    return this.expireActions;
  }

  public Map getInfo() {
    return this.info;
  }

  public void setInfo(final Map info) {
    this.info = info;
  }

  public Map getContext() {
    return this.context;
  }

  public void setContext(final Map context) {
    this.context = context;
  }

  public boolean isResetOnTrigger() {
    return this.resetOnTrigger;
  }

  public void setResetOnTrigger(final boolean resetOnTrigger) {
    this.resetOnTrigger = resetOnTrigger;
  }

  public boolean isResetOnExpire() {
    return this.resetOnExpire;
  }

  public void setResetOnExpire(final boolean resetOnExpire) {
    this.resetOnExpire = resetOnExpire;
  }

  public long getLastModifyTime() {
    return this.lastModifyTime;
  }

  public void setLastModifyTime(final long lastModifyTime) {
    this.lastModifyTime = lastModifyTime;
  }

  public int getTriggerId() {
    return this.triggerId;
  }

  public void setTriggerId(final int id) {
    this.triggerId = id;
  }

  public boolean triggerConditionMet() {
    return this.triggerCondition.isMet();
  }

  public boolean expireConditionMet() {
    return this.expireCondition.isMet();
  }

  public void resetTriggerConditions() {
    this.triggerCondition.resetCheckers();
    updateNextCheckTime();
  }

  public void resetExpireCondition() {
    this.expireCondition.resetCheckers();
    updateNextCheckTime();
  }

  public List getTriggerActions() {
    return this.actions;
  }

  public Map toJson() {
    final Map jsonObj = new HashMap<>();
    jsonObj.put("triggerCondition", this.triggerCondition.toJson());
    jsonObj.put("expireCondition", this.expireCondition.toJson());
    final List actionsJson = new ArrayList<>();
    for (final TriggerAction action : this.actions) {
      final Map oneActionJson = new HashMap<>();
      oneActionJson.put("type", action.getType());
      oneActionJson.put("actionJson", action.toJson());
      actionsJson.add(oneActionJson);
    }
    jsonObj.put("actions", actionsJson);
    final List expireActionsJson = new ArrayList<>();
    for (final TriggerAction expireAction : this.expireActions) {
      final Map oneExpireActionJson = new HashMap<>();
      oneExpireActionJson.put("type", expireAction.getType());
      oneExpireActionJson.put("actionJson", expireAction.toJson());
      expireActionsJson.add(oneExpireActionJson);
    }
    jsonObj.put("expireActions", expireActionsJson);

    jsonObj.put("resetOnTrigger", String.valueOf(this.resetOnTrigger));
    jsonObj.put("resetOnExpire", String.valueOf(this.resetOnExpire));
    jsonObj.put("submitUser", this.submitUser);
    jsonObj.put("source", this.source);
    jsonObj.put("submitTime", String.valueOf(this.submitTime));
    jsonObj.put("lastModifyTime", String.valueOf(this.lastModifyTime));
    jsonObj.put("triggerId", String.valueOf(this.triggerId));
    jsonObj.put("status", this.status.toString());
    jsonObj.put("info", this.info);
    jsonObj.put("context", this.context);
    return jsonObj;
  }

  public String getSource() {
    return this.source;
  }

  public String getDescription() {
    final StringBuffer actionsString = new StringBuffer();
    for (final TriggerAction act : this.actions) {
      actionsString.append(", ");
      actionsString.append(act.getDescription());
    }
    return "Trigger from " + getSource() + " with trigger condition of "
        + this.triggerCondition.getExpression() + " and expire condition of "
        + this.expireCondition.getExpression() + actionsString;
  }

  public void stopCheckers() {
    for (final ConditionChecker checker : this.triggerCondition.getCheckers().values()) {
      checker.stopChecker();
    }
    for (final ConditionChecker checker : this.expireCondition.getCheckers().values()) {
      checker.stopChecker();
    }
  }

  @Override
  public String toString() {
    return "Trigger Id: " + getTriggerId() + ", Description: " + getDescription();
  }

  public static class TriggerBuilder {

    private final String submitUser;
    private final String source;
    private final TriggerStatus status = TriggerStatus.READY;
    private final Condition triggerCondition;
    private final List actions;
    private final Condition expireCondition;
    private int triggerId = -1;
    private long lastModifyTime;
    private long submitTime;
    private List expireActions = new ArrayList<>();

    private Map info = new HashMap<>();
    private Map context = new HashMap<>();

    public TriggerBuilder(final String submitUser,
        final String source,
        final Condition triggerCondition,
        final Condition expireCondition,
        final List actions) {
      this.submitUser = submitUser;
      this.source = source;
      this.triggerCondition = triggerCondition;
      this.actions = actions;
      this.expireCondition = expireCondition;
      final long now = DateTime.now().getMillis();
      this.submitTime = now;
      this.lastModifyTime = now;
    }

    public TriggerBuilder setId(final int id) {
      this.triggerId = id;
      return this;
    }

    public TriggerBuilder setSubmitTime(final long time) {
      this.submitTime = time;
      return this;
    }

    public TriggerBuilder setLastModifyTime(final long time) {
      this.lastModifyTime = time;
      return this;
    }

    public TriggerBuilder setExpireActions(final List actions) {
      this.expireActions = actions;
      return this;
    }

    public TriggerBuilder setInfo(final Map info) {
      this.info = info;
      return this;
    }

    public TriggerBuilder setContext(final Map context) {
      this.context = context;
      return this;
    }

    public Trigger build() {
      return new Trigger(this.triggerId,
          this.lastModifyTime,
          this.submitTime,
          this.submitUser,
          this.source,
          this.triggerCondition,
          this.expireCondition,
          this.actions,
          this.expireActions,
          this.info,
          this.context);
    }
  }

}