/**
  * Return Job Name.
  *
  * <p>
  *
  * @return coordinator name
  */
 public static String ph2_coord_name() throws Exception {
   ELEvaluator eval = ELEvaluator.getCurrent();
   SyncCoordAction action =
       ParamChecker.notNull(
           (SyncCoordAction) eval.getVariable(COORD_ACTION), "Coordinator Action");
   return action.getName();
 }
 /**
  * Return nominal time or Action Creation Time.
  *
  * <p>
  *
  * @return coordinator action creation or materialization date time
  * @throws Exception if unable to format the Date object to String
  */
 public static String ph2_coord_nominalTime() throws Exception {
   ELEvaluator eval = ELEvaluator.getCurrent();
   SyncCoordAction action =
       ParamChecker.notNull(
           (SyncCoordAction) eval.getVariable(COORD_ACTION), "Coordinator Action");
   return DateUtils.formatDateUTC(action.getNominalTime());
 }
 /**
  * Used in defining the frequency in 'month' unit and specify the "end of month" property.
  *
  * <p>Every instance will start at first day of each month at 00:00 hour.
  *
  * <p>domain: <code> val &gt; 0</code> and should be integer.
  *
  * @param val: frequency in number of months.
  * @return number of months and also set the frequency timeunit to "month" and end_of_duration
  *     flag to "month"
  */
 public static int ph1_coord_endOfMonths(int val) {
   val = ParamChecker.checkGTZero(val, "n");
   ELEvaluator eval = ELEvaluator.getCurrent();
   eval.setVariable("timeunit", TimeUnit.MONTH);
   eval.setVariable("endOfDuration", TimeUnit.END_OF_MONTH);
   return val;
 }
 /**
  * Used in defining the frequency in 'minute' unit.
  *
  * <p>domain: <code> val &gt; 0</code> and should be integer.
  *
  * @param val frequency in number of minutes.
  * @return number of minutes and also set the frequency timeunit to "minute"
  */
 public static int ph1_coord_minutes(int val) {
   val = ParamChecker.checkGTZero(val, "n");
   ELEvaluator eval = ELEvaluator.getCurrent();
   eval.setVariable("timeunit", TimeUnit.MINUTE);
   eval.setVariable("endOfDuration", TimeUnit.NONE);
   return val;
 }
 /** @return dataset TimeUnit */
 private static TimeUnit getDSEndOfFlag() {
   ELEvaluator eval = ELEvaluator.getCurrent();
   SyncCoordDataset ds = (SyncCoordDataset) eval.getVariable(DATASET);
   if (ds == null) {
     throw new RuntimeException("Associated Dataset should be defined with key " + DATASET);
   }
   return ds.getEndOfDuration(); // == null ? "": ds.getEndOfDuration();
 }
 /** @return whether a data set is SYNCH or ASYNC */
 private static boolean isSyncDataSet() {
   ELEvaluator eval = ELEvaluator.getCurrent();
   SyncCoordDataset ds = (SyncCoordDataset) eval.getVariable(DATASET);
   if (ds == null) {
     throw new RuntimeException("Associated Dataset should be defined with key " + DATASET);
   }
   return ds.getType().equalsIgnoreCase("SYNC");
 }
 /** @return dataset TimeZone */
 private static TimeZone getDatasetTZ() {
   ELEvaluator eval = ELEvaluator.getCurrent();
   SyncCoordDataset ds = (SyncCoordDataset) eval.getVariable(DATASET);
   if (ds == null) {
     throw new RuntimeException("Associated Dataset should be defined with key " + DATASET);
   }
   return ds.getTimeZone();
 }
 /**
  * Return Action Start time.
  *
  * <p>
  *
  * @return coordinator action start time
  * @throws Exception if unable to format the Date object to String
  */
 public static String ph2_coord_actualTime() throws Exception {
   ELEvaluator eval = ELEvaluator.getCurrent();
   SyncCoordAction coordAction = (SyncCoordAction) eval.getVariable(COORD_ACTION);
   if (coordAction == null) {
     throw new RuntimeException(
         "Associated Application instance should be defined with key " + COORD_ACTION);
   }
   return DateUtils.formatDateUTC(coordAction.getActualTime());
 }
 public static String ph1_coord_dataOut_echo(String n) {
   ELEvaluator eval = ELEvaluator.getCurrent();
   String val = (String) eval.getVariable("oozie.dataname." + n);
   if (val == null || val.equals("data-out") == false) {
     XLog.getLog(CoordELFunctions.class).error("data_out_name " + n + " is not valid");
     throw new RuntimeException("data_out_name " + n + " is not valid");
   }
   return echoUnResolved("dataOut", "'" + n + "'");
 }
 /** @return Actual Time when all the dependencies of an application instance are met. */
 private static Date getActualTime() {
   ELEvaluator eval = ELEvaluator.getCurrent();
   SyncCoordAction coordAction = (SyncCoordAction) eval.getVariable(COORD_ACTION);
   if (coordAction == null) {
     throw new RuntimeException(
         "Associated Application instance should be defined with key " + COORD_ACTION);
   }
   return coordAction.getActualTime();
 }
 /**
  * Used to specify a list of URI's that are used as input dir to the workflow job.
  *
  * <p>Look for two evaluator-level variables
  *
  * <p>A) .datain.<DATAIN_NAME> B) .datain.<DATAIN_NAME>.unresolved
  *
  * <p>A defines the current list of URI.
  *
  * <p>B defines whether there are any unresolved EL-function (i.e latest)
  *
  * <p>If there are something unresolved, this function will echo back the original function
  *
  * <p>otherwise it sends the uris.
  *
  * @param dataInName : Datain name
  * @return the list of URI's separated by INSTANCE_SEPARATOR
  *     <p>if there are unresolved EL function (i.e. latest) , echo back
  *     <p>the function without resolving the function.
  */
 public static String ph3_coord_dataIn(String dataInName) {
   String uris = "";
   ELEvaluator eval = ELEvaluator.getCurrent();
   uris = (String) eval.getVariable(".datain." + dataInName);
   Boolean unresolved = (Boolean) eval.getVariable(".datain." + dataInName + ".unresolved");
   if (unresolved != null && unresolved.booleanValue() == true) {
     return "${coord:dataIn('" + dataInName + "')}";
   }
   return uris;
 }
 /**
  * Check whether a function should be resolved.
  *
  * @param functionName
  * @param n
  * @return null if the functionName needs to be resolved otherwise return the calling function
  *     unresolved.
  */
 private static String checkIfResolved(String functionName, String n) {
   ELEvaluator eval = ELEvaluator.getCurrent();
   String replace = (String) eval.getVariable("resolve_" + functionName);
   if (replace == null || (replace != null && replace.equalsIgnoreCase("false"))) { // Don't
     // resolve
     // return "${coord:" + functionName + "(" + n +")}"; //Unresolved
     eval.setVariable(".wrap", "true");
     return "coord:" + functionName + "(" + n + ")"; // Unresolved
   }
   return null; // Resolved it
 }
 /** @return the initial instance of a DataSet in Calendar */
 private static Calendar getInitialInstanceCal() {
   ELEvaluator eval = ELEvaluator.getCurrent();
   SyncCoordDataset ds = (SyncCoordDataset) eval.getVariable(DATASET);
   if (ds == null) {
     throw new RuntimeException("Associated Dataset should be defined with key " + DATASET);
   }
   Calendar effInitTS = Calendar.getInstance();
   effInitTS.setTime(ds.getInitInstance());
   effInitTS.setTimeZone(ds.getTimeZone());
   // To adjust EOD/EOM
   DateUtils.moveToEnd(effInitTS, getDSEndOfFlag());
   return effInitTS;
   // return ds.getInitInstance();
 }
 /**
  * Used to specify a list of URI's that are output dir of the workflow job.
  *
  * <p>Look for one evaluator-level variable
  *
  * <p>dataout.<DATAOUT_NAME>
  *
  * <p>It defines the current list of URI.
  *
  * <p>otherwise it sends the uris.
  *
  * @param dataOutName : Dataout name
  * @return the list of URI's separated by INSTANCE_SEPARATOR
  */
 public static String ph3_coord_dataOut(String dataOutName) {
   String uris = "";
   ELEvaluator eval = ELEvaluator.getCurrent();
   uris = (String) eval.getVariable(".dataout." + dataOutName);
   return uris;
 }
 /**
  * Return the user that submitted the coordinator job.
  *
  * @return the user that submitted the coordinator job.
  */
 public static String coord_user() {
   ELEvaluator eval = ELEvaluator.getCurrent();
   return (String) eval.getVariable(OozieClient.USER_NAME);
 }
 private static String echoUnResolvedPre(String functionName, String n, String prefix) {
   ELEvaluator eval = ELEvaluator.getCurrent();
   eval.setVariable(".wrap", "true");
   return prefix + functionName + "(" + n + ")"; // Unresolved
 }
  /**
   * @param offset
   * @return n-th available latest instance Date-Time for SYNC data-set
   * @throws Exception
   */
  private static String coord_latest_sync(int offset) throws Exception {
    if (offset > 0) {
      throw new RuntimeException(
          "For latest there is no meaning " + "of positive instance. n should be <=0" + offset);
    }
    ELEvaluator eval = ELEvaluator.getCurrent();
    String retVal = "";
    int datasetFrequency = (int) getDSFrequency(); // in minutes
    TimeUnit dsTimeUnit = getDSTimeUnit();
    int[] instCount = new int[1];
    Calendar nominalInstanceCal = getCurrentInstance(getActualTime(), instCount);
    if (nominalInstanceCal != null) {
      Calendar initInstance = getInitialInstanceCal();
      SyncCoordDataset ds = (SyncCoordDataset) eval.getVariable(DATASET);
      if (ds == null) {
        throw new RuntimeException("Associated Dataset should be defined with key " + DATASET);
      }
      String uriTemplate = ds.getUriTemplate();
      Configuration conf = (Configuration) eval.getVariable(CONFIGURATION);
      if (conf == null) {
        throw new RuntimeException(
            "Associated Configuration should be defined with key " + CONFIGURATION);
      }
      int available = 0;
      boolean resolved = false;
      String user =
          ParamChecker.notEmpty(
              (String) eval.getVariable(OozieClient.USER_NAME), OozieClient.USER_NAME);
      String group =
          ParamChecker.notEmpty(
              (String) eval.getVariable(OozieClient.GROUP_NAME), OozieClient.GROUP_NAME);
      String doneFlag = ds.getDoneFlag();
      while (nominalInstanceCal.compareTo(initInstance) >= 0) {
        ELEvaluator uriEval = getUriEvaluator(nominalInstanceCal);
        String uriPath = uriEval.evaluate(uriTemplate, String.class);
        String pathWithDoneFlag = uriPath;
        if (doneFlag.length() > 0) {
          pathWithDoneFlag += "/" + doneFlag;
        }
        if (isPathAvailable(pathWithDoneFlag, user, group, conf)) {
          XLog.getLog(CoordELFunctions.class)
              .debug("Found latest(" + available + "): " + pathWithDoneFlag);
          if (available == offset) {
            XLog.getLog(CoordELFunctions.class).debug("Found Latest File: " + pathWithDoneFlag);
            resolved = true;
            retVal = DateUtils.formatDateUTC(nominalInstanceCal);
            eval.setVariable("resolved_path", uriPath);
            break;
          }

          available--;
        }
        // nominalInstanceCal.add(dsTimeUnit.getCalendarUnit(),
        // -datasetFrequency);
        nominalInstanceCal = (Calendar) initInstance.clone();
        instCount[0]--;
        nominalInstanceCal.add(dsTimeUnit.getCalendarUnit(), instCount[0] * datasetFrequency);
        // DateUtils.moveToEnd(nominalInstanceCal, getDSEndOfFlag());
      }
      if (!resolved) {
        // return unchanged latest function with variable 'is_resolved'
        // to 'false'
        eval.setVariable("is_resolved", Boolean.FALSE);
        retVal = "${coord:latest(" + offset + ")}";
      } else {
        eval.setVariable("is_resolved", Boolean.TRUE);
      }
    } else { // No feasible nominal time
      eval.setVariable("is_resolved", Boolean.FALSE);
    }
    return retVal;
  }