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 java.io.IOException;
018    import java.io.Writer;
019    import java.util.ArrayList;
020    import java.util.Date;
021    import java.util.HashMap;
022    import java.util.HashSet;
023    import java.util.List;
024    import java.util.Map;
025    import java.util.Set;
026    import java.util.StringTokenizer;
027    
028    import org.apache.hadoop.conf.Configuration;
029    import org.apache.oozie.client.CoordinatorJob;
030    import org.apache.oozie.client.OozieClient;
031    import org.apache.oozie.client.WorkflowJob;
032    import org.apache.oozie.command.CommandException;
033    import org.apache.oozie.command.coord.CoordActionInfoCommand;
034    import org.apache.oozie.command.coord.CoordJobCommand;
035    import org.apache.oozie.command.coord.CoordJobsCommand;
036    import org.apache.oozie.command.coord.CoordKillCommand;
037    import org.apache.oozie.command.coord.CoordRerunCommand;
038    import org.apache.oozie.command.coord.CoordChangeCommand;
039    import org.apache.oozie.command.coord.CoordResumeCommand;
040    import org.apache.oozie.command.coord.CoordSubmitCommand;
041    import org.apache.oozie.command.coord.CoordSuspendCommand;
042    import org.apache.oozie.service.DagXLogInfoService;
043    import org.apache.oozie.service.Services;
044    import org.apache.oozie.service.XLogService;
045    import org.apache.oozie.util.ParamChecker;
046    import org.apache.oozie.util.XLog;
047    import org.apache.oozie.util.XLogStreamer;
048    
049    public class CoordinatorEngine extends BaseEngine {
050    
051        /**
052         * Create a system Coordinator engine, with no user and no group.
053         */
054        public CoordinatorEngine() {
055        }
056    
057        /**
058         * Create a Coordinator engine to perform operations on behave of a user.
059         *
060         * @param user user name.
061         * @param authToken the authentication token.
062         */
063        public CoordinatorEngine(String user, String authToken) {
064            this.user = ParamChecker.notEmpty(user, "user");
065            this.authToken = ParamChecker.notEmpty(authToken, "authToken");
066        }
067    
068        /*
069         * (non-Javadoc)
070         *
071         * @see org.apache.oozie.BaseEngine#getDefinition(java.lang.String)
072         */
073        @Override
074        public String getDefinition(String jobId) throws BaseEngineException {
075            CoordinatorJobBean job = getCoordJobWithNoActionInfo(jobId);
076            return job.getOrigJobXml();
077        }
078    
079        /**
080         * @param jobId
081         * @return CoordinatorJobBean
082         * @throws BaseEngineException
083         */
084        private CoordinatorJobBean getCoordJobWithNoActionInfo(String jobId) throws BaseEngineException {
085            try {
086                return new CoordJobCommand(jobId, false).call();
087            }
088            catch (CommandException ex) {
089                throw new BaseEngineException(ex);
090            }
091        }
092    
093        /**
094         * @param actionId
095         * @return CoordinatorActionBean
096         * @throws BaseEngineException
097         */
098        public CoordinatorActionBean getCoordAction(String actionId) throws BaseEngineException {
099            try {
100                return new CoordActionInfoCommand(actionId).call();
101            }
102            catch (CommandException ex) {
103                throw new BaseEngineException(ex);
104            }
105        }
106    
107        /*
108         * (non-Javadoc)
109         *
110         * @see org.apache.oozie.BaseEngine#getCoordJob(java.lang.String)
111         */
112        @Override
113        public CoordinatorJobBean getCoordJob(String jobId) throws BaseEngineException {
114            try {
115                return new CoordJobCommand(jobId).call();
116            }
117            catch (CommandException ex) {
118                throw new BaseEngineException(ex);
119            }
120        }
121    
122        /*
123         * (non-Javadoc)
124         *
125         * @see org.apache.oozie.BaseEngine#getCoordJob(java.lang.String, int, int)
126         */
127        @Override
128        public CoordinatorJobBean getCoordJob(String jobId, int start, int length) throws BaseEngineException {
129            try {
130                return new CoordJobCommand(jobId, start, length).call();
131            }
132            catch (CommandException ex) {
133                throw new BaseEngineException(ex);
134            }
135        }
136    
137        /*
138         * (non-Javadoc)
139         *
140         * @see org.apache.oozie.BaseEngine#getJobIdForExternalId(java.lang.String)
141         */
142        @Override
143        public String getJobIdForExternalId(String externalId) throws CoordinatorEngineException {
144            return null;
145        }
146    
147        /*
148         * (non-Javadoc)
149         *
150         * @see org.apache.oozie.BaseEngine#kill(java.lang.String)
151         */
152        @Override
153        public void kill(String jobId) throws CoordinatorEngineException {
154            try {
155                new CoordKillCommand(jobId).call();
156                XLog.getLog(getClass()).info("User " + user + " killed the Coordinator job " + jobId);
157            }
158            catch (CommandException e) {
159                throw new CoordinatorEngineException(e);
160            }
161        }
162    
163        /* (non-Javadoc)
164         * @see org.apache.oozie.BaseEngine#change(java.lang.String, java.lang.String)
165         */
166        @Override
167        public void change(String jobId, String changeValue) throws CoordinatorEngineException {
168            try {
169                new CoordChangeCommand(jobId, changeValue).call();
170                XLog.getLog(getClass()).info("User " + user + " changed the Coordinator job " + jobId + " to " + changeValue);
171            }
172            catch (CommandException e) {
173                throw new CoordinatorEngineException(e);
174            }
175        }
176    
177        @Override
178        @Deprecated
179        public void reRun(String jobId, Configuration conf) throws BaseEngineException {
180            throw new BaseEngineException(new XException(ErrorCode.E0301));
181        }
182    
183        /**
184         * Rerun coordinator actions for given rerunType
185         *
186         * @param jobId
187         * @param rerunType
188         * @param scope
189         * @param refresh
190         * @param noCleanup
191         * @throws BaseEngineException
192         */
193        public CoordinatorActionInfo reRun(String jobId, String rerunType, String scope, boolean refresh, boolean noCleanup)
194                throws BaseEngineException {
195            try {
196                return new CoordRerunCommand(jobId, rerunType, scope, refresh, noCleanup).call();
197            }
198            catch (CommandException ex) {
199                throw new BaseEngineException(ex);
200            }
201        }
202    
203        /*
204         * (non-Javadoc)
205         *
206         * @see org.apache.oozie.BaseEngine#resume(java.lang.String)
207         */
208        @Override
209        public void resume(String jobId) throws CoordinatorEngineException {
210            try {
211                new CoordResumeCommand(jobId).call();
212            }
213            catch (CommandException e) {
214                throw new CoordinatorEngineException(e);
215            }
216        }
217    
218        @Override
219        @Deprecated
220        public void start(String jobId) throws BaseEngineException {
221            throw new BaseEngineException(new XException(ErrorCode.E0301));
222        }
223    
224        /*
225         * (non-Javadoc)
226         *
227         * @see org.apache.oozie.BaseEngine#streamLog(java.lang.String,
228         * java.io.Writer)
229         */
230        @Override
231        public void streamLog(String jobId, Writer writer) throws IOException, BaseEngineException {
232            XLogStreamer.Filter filter = new XLogStreamer.Filter();
233            filter.setParameter(DagXLogInfoService.JOB, jobId);
234    
235            CoordinatorJobBean job = getCoordJobWithNoActionInfo(jobId);
236            Services.get().get(XLogService.class).streamLog(filter, job.getCreatedTime(), new Date(), writer);
237    
238        }
239    
240        /*
241         * (non-Javadoc)
242         *
243         * @see
244         * org.apache.oozie.BaseEngine#submitJob(org.apache.hadoop.conf.Configuration
245         * , boolean)
246         */
247        @Override
248        public String submitJob(Configuration conf, boolean startJob) throws CoordinatorEngineException {
249            CoordSubmitCommand submit = new CoordSubmitCommand(conf, getAuthToken());
250            try {
251                String jobId = submit.call();
252                return jobId;
253            }
254            catch (CommandException ex) {
255                throw new CoordinatorEngineException(ex);
256            }
257        }
258    
259        /*
260         * (non-Javadoc)
261         *
262         * @see
263         * org.apache.oozie.BaseEngine#dryrunSubmit(org.apache.hadoop.conf.Configuration
264         * , boolean)
265         */
266        @Override
267        public String dryrunSubmit(Configuration conf, boolean startJob) throws CoordinatorEngineException {
268            CoordSubmitCommand submit = new CoordSubmitCommand(true, conf, getAuthToken());
269            try {
270                String jobId = submit.call();
271                return jobId;
272            }
273            catch (CommandException ex) {
274                throw new CoordinatorEngineException(ex);
275            }
276        }
277    
278        /*
279         * (non-Javadoc)
280         *
281         * @see org.apache.oozie.BaseEngine#suspend(java.lang.String)
282         */
283        @Override
284        public void suspend(String jobId) throws CoordinatorEngineException {
285            try {
286                new CoordSuspendCommand(jobId).call();
287            }
288            catch (CommandException e) {
289                throw new CoordinatorEngineException(e);
290            }
291    
292        }
293    
294        /*
295         * (non-Javadoc)
296         *
297         * @see org.apache.oozie.BaseEngine#getJob(java.lang.String)
298         */
299        @Override
300        public WorkflowJob getJob(String jobId) throws BaseEngineException {
301            throw new BaseEngineException(new XException(ErrorCode.E0301));
302        }
303    
304        /*
305         * (non-Javadoc)
306         *
307         * @see org.apache.oozie.BaseEngine#getJob(java.lang.String, int, int)
308         */
309        @Override
310        public WorkflowJob getJob(String jobId, int start, int length) throws BaseEngineException {
311            throw new BaseEngineException(new XException(ErrorCode.E0301));
312        }
313    
314        private static final Set<String> FILTER_NAMES = new HashSet<String>();
315    
316        static {
317            FILTER_NAMES.add(OozieClient.FILTER_USER);
318            FILTER_NAMES.add(OozieClient.FILTER_NAME);
319            FILTER_NAMES.add(OozieClient.FILTER_GROUP);
320            FILTER_NAMES.add(OozieClient.FILTER_STATUS);
321        }
322    
323        /**
324         * @param filterStr
325         * @param start
326         * @param len
327         * @return CoordinatorJobInfo
328         * @throws CoordinatorEngineException
329         */
330        public CoordinatorJobInfo getCoordJobs(String filterStr, int start, int len) throws CoordinatorEngineException {
331            Map<String, List<String>> filter = parseFilter(filterStr);
332    
333            try {
334                return new CoordJobsCommand(filter, start, len).call();
335            }
336            catch (CommandException ex) {
337                throw new CoordinatorEngineException(ex);
338            }
339        }
340    
341        /**
342         * @param filter
343         * @return Map<String, List<String>>
344         * @throws CoordinatorEngineException
345         */
346        private Map<String, List<String>> parseFilter(String filter) throws CoordinatorEngineException {
347            Map<String, List<String>> map = new HashMap<String, List<String>>();
348            if (filter != null) {
349                StringTokenizer st = new StringTokenizer(filter, ";");
350                while (st.hasMoreTokens()) {
351                    String token = st.nextToken();
352                    if (token.contains("=")) {
353                        String[] pair = token.split("=");
354                        if (pair.length != 2) {
355                            throw new CoordinatorEngineException(ErrorCode.E0420, filter,
356                                                                 "elements must be name=value pairs");
357                        }
358                        if (!FILTER_NAMES.contains(pair[0])) {
359                            throw new CoordinatorEngineException(ErrorCode.E0420, filter, XLog.format("invalid name [{0}]",
360                                                                                                      pair[0]));
361                        }
362                        if (pair[0].equals("status")) {
363                            try {
364                                CoordinatorJob.Status.valueOf(pair[1]);
365                            }
366                            catch (IllegalArgumentException ex) {
367                                throw new CoordinatorEngineException(ErrorCode.E0420, filter, XLog.format(
368                                        "invalid status [{0}]", pair[1]));
369                            }
370                        }
371                        List<String> list = map.get(pair[0]);
372                        if (list == null) {
373                            list = new ArrayList<String>();
374                            map.put(pair[0], list);
375                        }
376                        list.add(pair[1]);
377                    }
378                    else {
379                        throw new CoordinatorEngineException(ErrorCode.E0420, filter, "elements must be name=value pairs");
380                    }
381                }
382            }
383            return map;
384        }
385    }