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.getErrorMessage() != 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    }