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 }