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