001 /** 002 * Copyright (c) 2010 Yahoo! Inc. All rights reserved. 003 * Licensed under the Apache License, Version 2.0 (the "License"); 004 * you may not use this file except in compliance with the License. 005 * You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software 010 * distributed under the License is distributed on an "AS IS" BASIS, 011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 * See the License for the specific language governing permissions and 013 * limitations under the License. See accompanying LICENSE file. 014 */ 015 package org.apache.oozie; 016 017 import org.apache.hadoop.conf.Configuration; 018 import org.apache.oozie.client.WorkflowAction; 019 import org.apache.oozie.service.CallbackService; 020 import org.apache.oozie.workflow.WorkflowInstance; 021 import org.apache.oozie.service.Services; 022 import org.apache.oozie.util.ELEvaluator; 023 import org.apache.oozie.util.PropertiesUtils; 024 import org.apache.oozie.util.XConfiguration; 025 import org.apache.oozie.util.ParamChecker; 026 027 import java.io.IOException; 028 import java.io.StringReader; 029 import java.util.Properties; 030 import java.util.Map; 031 032 /** 033 * DAG EL functions. 034 */ 035 public class DagELFunctions { 036 037 private static final String WORKFLOW = "oozie.el.workflow.bean"; 038 private static final String ACTION = "oozie.el.action.bean"; 039 private static final String ACTION_PROTO_CONF = "oozie.el.action.proto.conf"; 040 041 private static final String LAST_ACTION_IN_ERROR = "oozie.el.last.action.in.error"; 042 043 private static final String ACTION_DATA = "action.data"; 044 private static final String ACTION_ERROR_CODE = "action.error.code"; 045 private static final String ACTION_ERROR_MESSAGE = "action.error.message"; 046 private static final String ACTION_EXTERNAL_ID = "action.external.id"; 047 private static final String ACTION_TRACKER_URI = "action.tracker.uri"; 048 private static final String ACTION_EXTERNAL_STATUS = "action.external.status"; 049 050 public static void configureEvaluator(ELEvaluator evaluator, WorkflowJobBean workflow, WorkflowActionBean action) { 051 evaluator.setVariable(WORKFLOW, workflow); 052 evaluator.setVariable(ACTION, action); 053 for (Map.Entry<String, String> entry : workflow.getWorkflowInstance().getConf()) { 054 if (ParamChecker.isValidIdentifier(entry.getKey())) { 055 evaluator.setVariable(entry.getKey().trim(), entry.getValue().trim()); 056 } 057 } 058 try { 059 evaluator.setVariable(ACTION_PROTO_CONF, 060 new XConfiguration(new StringReader(workflow.getProtoActionConf()))); 061 } 062 catch (IOException ex) { 063 throw new RuntimeException("It should not happen", ex); 064 } 065 } 066 067 public static WorkflowActionBean getAction() { 068 ELEvaluator eval = ELEvaluator.getCurrent(); 069 return (WorkflowActionBean) eval.getVariable(ACTION); 070 } 071 072 public static WorkflowJobBean getWorkflow() { 073 ELEvaluator eval = ELEvaluator.getCurrent(); 074 return (WorkflowJobBean) eval.getVariable(WORKFLOW); 075 } 076 077 public static Configuration getProtoActionConf() { 078 ELEvaluator eval = ELEvaluator.getCurrent(); 079 return (Configuration) eval.getVariable(ACTION_PROTO_CONF); 080 } 081 082 public static void setActionInfo(WorkflowInstance workflowInstance, WorkflowAction action) { 083 if (action.getExternalId() != null) { 084 workflowInstance.setVar(action.getName() + WorkflowInstance.NODE_VAR_SEPARATOR + ACTION_EXTERNAL_ID, 085 action.getExternalId()); 086 } 087 if (action.getTrackerUri() != null) { 088 workflowInstance.setVar(action.getName() + WorkflowInstance.NODE_VAR_SEPARATOR + ACTION_TRACKER_URI, 089 action.getTrackerUri()); 090 } 091 if (action.getExternalStatus() != null) { 092 workflowInstance.setVar(action.getName() + WorkflowInstance.NODE_VAR_SEPARATOR + ACTION_EXTERNAL_STATUS, 093 action.getExternalStatus()); 094 } 095 if (action.getData() != null) { 096 workflowInstance 097 .setVar(action.getName() + WorkflowInstance.NODE_VAR_SEPARATOR + ACTION_DATA, action.getData()); 098 } 099 if (action.getErrorCode() != null) { 100 workflowInstance.setVar(action.getName() + WorkflowInstance.NODE_VAR_SEPARATOR + ACTION_ERROR_CODE, 101 action.getErrorCode()); 102 } 103 if (action.getData() != null) { 104 workflowInstance.setVar(action.getName() + WorkflowInstance.NODE_VAR_SEPARATOR + ACTION_ERROR_MESSAGE, 105 action.getErrorMessage()); 106 } 107 if (action.getStatus() == WorkflowAction.Status.ERROR) { 108 workflowInstance.setVar(LAST_ACTION_IN_ERROR, action.getName()); 109 } 110 } 111 112 /** 113 * Return the job Id. 114 * 115 * @return the job Id. 116 */ 117 public static String wf_id() { 118 return getWorkflow().getId(); 119 } 120 121 /** 122 * Return the application name. 123 * 124 * @return the application name. 125 */ 126 public static String wf_name() { 127 return getWorkflow().getAppName(); 128 } 129 130 /** 131 * Return the application path. 132 * 133 * @return the application path. 134 */ 135 public static String wf_appPath() { 136 return getWorkflow().getAppPath(); 137 } 138 139 /** 140 * Return a job configuration property. 141 * 142 * @param property property name. 143 * @return the value of the property, <code>null</code> if the property is undefined. 144 */ 145 public static String wf_conf(String property) { 146 return getWorkflow().getWorkflowInstance().getConf().get(property); 147 } 148 149 /** 150 * Return the job owner user name. 151 * 152 * @return the job owner user name. 153 */ 154 public static String wf_user() { 155 return getWorkflow().getUser(); 156 } 157 158 /** 159 * Return the job owner group name. 160 * 161 * @return the job owner group name. 162 */ 163 public static String wf_group() { 164 return getWorkflow().getGroup(); 165 } 166 167 /** 168 * Create a callback URL for the current action. 169 * 170 * @param externalStatusVar variable for the caller to inject the external status. 171 * @return the callback URL for the current action. 172 */ 173 public static String wf_callback(String externalStatusVar) { 174 return Services.get().get(CallbackService.class).createCallBackUrl(getAction().getId(), externalStatusVar); 175 } 176 177 /** 178 * Return the transition taken by a workflow job action/decision action. 179 * 180 * @param actionName action/decision action name. 181 * @return the transition taken, <code>null</code> if the action has not completed yet. 182 */ 183 public static String wf_transition(String actionName) { 184 return getWorkflow().getWorkflowInstance().getTransition(actionName); 185 } 186 187 /** 188 * Return the name of the last action that ended in error. 189 * 190 * @return the name of the last action that ended in error, <code>null</code> if no action in the workflow job has 191 * ended in error. 192 */ 193 public static String wf_lastErrorNode() { 194 return getWorkflow().getWorkflowInstance().getVar(LAST_ACTION_IN_ERROR); 195 } 196 197 /** 198 * Return the error code for an action. 199 * 200 * @param actionName action name. 201 * @return the error code for the action, <code>null</code> if the action has not ended in error. 202 */ 203 public static String wf_errorCode(String actionName) { 204 return getWorkflow().getWorkflowInstance() 205 .getVar(actionName + WorkflowInstance.NODE_VAR_SEPARATOR + ACTION_ERROR_CODE); 206 } 207 208 /** 209 * Return the error message for an action. 210 * 211 * @param actionName action name. 212 * @return the error message for the action, <code>null</code> if the action has not ended in error. 213 */ 214 public static String wf_errorMessage(String actionName) { 215 return getWorkflow().getWorkflowInstance() 216 .getVar(actionName + WorkflowInstance.NODE_VAR_SEPARATOR + ACTION_ERROR_MESSAGE); 217 } 218 219 /** 220 * Return the workflow run number, unless a rerun it is always 1. 221 * 222 * @return the workflow run number, unless a rerun it is always 1. 223 */ 224 public static int wf_run() { 225 return getWorkflow().getRun(); 226 } 227 228 /** 229 * Return the action data for an action. 230 * 231 * @param actionName action name. 232 * @return value of the property. 233 */ 234 @SuppressWarnings("unchecked") 235 public static Map<String, String> wf_actionData(String actionName) { 236 ELEvaluator eval = ELEvaluator.getCurrent(); 237 Properties props = (Properties) eval.getVariable(actionName + ACTION_ERROR_MESSAGE); 238 239 if (props == null) { 240 String data = getWorkflow().getWorkflowInstance() 241 .getVar(actionName + WorkflowInstance.NODE_VAR_SEPARATOR + ACTION_DATA); 242 if (data != null) { 243 props = PropertiesUtils.stringToProperties(data); 244 } 245 else { 246 props = new Properties(); 247 } 248 eval.setVariable(actionName + ACTION_ERROR_MESSAGE, props); 249 } 250 return (Map<String, String>) (Map) props; 251 } 252 253 /** 254 * Return the external ID of an action. 255 * 256 * @param actionName action name. 257 * @return the external ID of an action. 258 */ 259 public static String wf_actionExternalId(String actionName) { 260 return getWorkflow().getWorkflowInstance() 261 .getVar(actionName + WorkflowInstance.NODE_VAR_SEPARATOR + ACTION_EXTERNAL_ID); 262 } 263 264 /** 265 * Return the tracker URI of an action. 266 * 267 * @param actionName action name. 268 * @return the tracker URI of an action. 269 */ 270 public static String wf_actionTrackerUri(String actionName) { 271 return getWorkflow().getWorkflowInstance() 272 .getVar(actionName + WorkflowInstance.NODE_VAR_SEPARATOR + ACTION_TRACKER_URI); 273 } 274 275 /** 276 * Return the action external status. 277 * 278 * @param actionName action/decision action name. 279 * @return the action external status. 280 */ 281 public static String wf_actionExternalStatus(String actionName) { 282 return getWorkflow().getWorkflowInstance() 283 .getVar(actionName + WorkflowInstance.NODE_VAR_SEPARATOR + ACTION_EXTERNAL_STATUS); 284 } 285 286 public static String getActionVar(String actionName, String varName) { 287 return getWorkflow().getWorkflowInstance().getVar(actionName + WorkflowInstance.NODE_VAR_SEPARATOR + varName); 288 } 289 290 }