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    package org.apache.oozie.cli;
019    
020    import java.io.File;
021    import java.io.FileInputStream;
022    import java.io.FileReader;
023    import java.io.IOException;
024    import java.io.InputStream;
025    import java.io.PrintStream;
026    import java.text.SimpleDateFormat;
027    import java.util.ArrayList;
028    import java.util.Date;
029    import java.util.List;
030    import java.util.Locale;
031    import java.util.Map;
032    import java.util.Properties;
033    import java.util.TimeZone;
034    import java.util.concurrent.Callable;
035    import java.util.regex.Matcher;
036    import java.util.regex.Pattern;
037    
038    import javax.xml.XMLConstants;
039    import javax.xml.parsers.DocumentBuilder;
040    import javax.xml.parsers.DocumentBuilderFactory;
041    import javax.xml.parsers.ParserConfigurationException;
042    import javax.xml.transform.stream.StreamSource;
043    import javax.xml.validation.Schema;
044    import javax.xml.validation.SchemaFactory;
045    import javax.xml.validation.Validator;
046    
047    import org.apache.commons.cli.CommandLine;
048    import org.apache.commons.cli.Option;
049    import org.apache.commons.cli.OptionBuilder;
050    import org.apache.commons.cli.OptionGroup;
051    import org.apache.commons.cli.Options;
052    import org.apache.commons.cli.ParseException;
053    import org.apache.oozie.BuildInfo;
054    import org.apache.oozie.client.AuthOozieClient;
055    import org.apache.oozie.client.BulkResponse;
056    import org.apache.oozie.client.BundleJob;
057    import org.apache.oozie.client.CoordinatorAction;
058    import org.apache.oozie.client.CoordinatorJob;
059    import org.apache.oozie.client.OozieClient;
060    import org.apache.oozie.client.OozieClientException;
061    import org.apache.oozie.client.WorkflowAction;
062    import org.apache.oozie.client.WorkflowJob;
063    import org.apache.oozie.client.XOozieClient;
064    import org.apache.oozie.client.OozieClient.SYSTEM_MODE;
065    import org.apache.oozie.client.rest.RestConstants;
066    import org.w3c.dom.DOMException;
067    import org.w3c.dom.Document;
068    import org.w3c.dom.Element;
069    import org.w3c.dom.Node;
070    import org.w3c.dom.NodeList;
071    import org.w3c.dom.Text;
072    import org.xml.sax.SAXException;
073    
074    /**
075     * Oozie command line utility.
076     */
077    public class OozieCLI {
078        public static final String ENV_OOZIE_URL = "OOZIE_URL";
079        public static final String ENV_OOZIE_DEBUG = "OOZIE_DEBUG";
080        public static final String ENV_OOZIE_TIME_ZONE = "OOZIE_TIMEZONE";
081        public static final String WS_HEADER_PREFIX = "header:";
082    
083        public static final String HELP_CMD = "help";
084        public static final String VERSION_CMD = "version";
085        public static final String JOB_CMD = "job";
086        public static final String JOBS_CMD = "jobs";
087        public static final String ADMIN_CMD = "admin";
088        public static final String VALIDATE_CMD = "validate";
089        public static final String SLA_CMD = "sla";
090        public static final String PIG_CMD = "pig";
091        public static final String MR_CMD = "mapreduce";
092        public static final String INFO_CMD = "info";
093    
094        public static final String OOZIE_OPTION = "oozie";
095        public static final String CONFIG_OPTION = "config";
096        public static final String SUBMIT_OPTION = "submit";
097        public static final String OFFSET_OPTION = "offset";
098        public static final String START_OPTION = "start";
099        public static final String RUN_OPTION = "run";
100        public static final String DRYRUN_OPTION = "dryrun";
101        public static final String SUSPEND_OPTION = "suspend";
102        public static final String RESUME_OPTION = "resume";
103        public static final String KILL_OPTION = "kill";
104        public static final String CHANGE_OPTION = "change";
105        public static final String CHANGE_VALUE_OPTION = "value";
106        public static final String RERUN_OPTION = "rerun";
107        public static final String INFO_OPTION = "info";
108        public static final String LOG_OPTION = "log";
109        public static final String ACTION_OPTION = "action";
110        public static final String DEFINITION_OPTION = "definition";
111        public static final String CONFIG_CONTENT_OPTION = "configcontent";
112    
113        public static final String DO_AS_OPTION = "doas";
114    
115        public static final String LEN_OPTION = "len";
116        public static final String FILTER_OPTION = "filter";
117        public static final String JOBTYPE_OPTION = "jobtype";
118        public static final String SYSTEM_MODE_OPTION = "systemmode";
119        public static final String VERSION_OPTION = "version";
120        public static final String STATUS_OPTION = "status";
121        public static final String LOCAL_TIME_OPTION = "localtime";
122        public static final String TIME_ZONE_OPTION = "timezone";
123        public static final String QUEUE_DUMP_OPTION = "queuedump";
124        public static final String RERUN_COORD_OPTION = "coordinator";
125        public static final String DATE_OPTION = "date";
126        public static final String RERUN_REFRESH_OPTION = "refresh";
127        public static final String RERUN_NOCLEANUP_OPTION = "nocleanup";
128    
129        public static final String AUTH_OPTION = "auth";
130    
131        public static final String VERBOSE_OPTION = "verbose";
132        public static final String VERBOSE_DELIMITER = "\t";
133        public static final String DEBUG_OPTION = "debug";
134    
135        public static final String PIGFILE_OPTION = "file";
136    
137        public static final String INFO_TIME_ZONES_OPTION = "timezones";
138    
139        public static final String BULK_OPTION = "bulk";
140    
141        private static final String[] OOZIE_HELP = {
142                "the env variable '" + ENV_OOZIE_URL + "' is used as default value for the '-" + OOZIE_OPTION + "' option",
143                "the env variable '" + ENV_OOZIE_TIME_ZONE + "' is used as default value for the '-" + TIME_ZONE_OPTION + "' option",
144                "custom headers for Oozie web services can be specified using '-D" + WS_HEADER_PREFIX + "NAME=VALUE'" };
145    
146        private static final String RULER;
147        private static final int LINE_WIDTH = 132;
148    
149        private boolean used;
150    
151        private static final String INSTANCE_SEPARATOR = "#";
152    
153        private static final String MAPRED_MAPPER = "mapred.mapper.class";
154        private static final String MAPRED_REDUCER = "mapred.reducer.class";
155        private static final String MAPRED_INPUT = "mapred.input.dir";
156        private static final String MAPRED_OUTPUT = "mapred.output.dir";
157    
158        private static final Pattern GMT_OFFSET_SHORTEN_PATTERN = Pattern.compile("(.* )GMT((?:-|\\+)\\d{2}:\\d{2})");
159    
160        static {
161            StringBuilder sb = new StringBuilder();
162            for (int i = 0; i < LINE_WIDTH; i++) {
163                sb.append("-");
164            }
165            RULER = sb.toString();
166        }
167    
168        /**
169         * Entry point for the Oozie CLI when invoked from the command line.
170         * <p/>
171         * Upon completion this method exits the JVM with '0' (success) or '-1' (failure).
172         *
173         * @param args options and arguments for the Oozie CLI.
174         */
175        public static void main(String[] args) {
176            if (!System.getProperties().contains(AuthOozieClient.USE_AUTH_TOKEN_CACHE_SYS_PROP)) {
177                System.setProperty(AuthOozieClient.USE_AUTH_TOKEN_CACHE_SYS_PROP, "true");
178            }
179            System.exit(new OozieCLI().run(args));
180        }
181    
182        /**
183         * Create an Oozie CLI instance.
184         */
185        public OozieCLI() {
186            used = false;
187        }
188    
189        /**
190         * Return Oozie CLI top help lines.
191         *
192         * @return help lines.
193         */
194        protected String[] getCLIHelp() {
195            return OOZIE_HELP;
196        }
197    
198        /**
199         * Add authentication specific options to oozie cli
200         *
201         * @param options the collection of options to add auth options
202         */
203        protected void addAuthOptions(Options options) {
204            Option auth = new Option(AUTH_OPTION, true, "select authentication type [SIMPLE|KERBEROS]");
205            options.addOption(auth);
206        }
207    
208        /**
209         * Create option for command line option 'admin'
210         * @return admin options
211         */
212        protected Options createAdminOptions() {
213            Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL");
214            Option system_mode = new Option(SYSTEM_MODE_OPTION, true,
215                    "Supported in Oozie-2.0 or later versions ONLY. Change oozie system mode [NORMAL|NOWEBSERVICE|SAFEMODE]");
216            Option status = new Option(STATUS_OPTION, false, "show the current system status");
217            Option version = new Option(VERSION_OPTION, false, "show Oozie server build version");
218            Option queuedump = new Option(QUEUE_DUMP_OPTION, false, "show Oozie server queue elements");
219            Option doAs = new Option(DO_AS_OPTION, true, "doAs user, impersonates as the specified user");
220            Options adminOptions = new Options();
221            adminOptions.addOption(oozie);
222            adminOptions.addOption(doAs);
223            OptionGroup group = new OptionGroup();
224            group.addOption(system_mode);
225            group.addOption(status);
226            group.addOption(version);
227            group.addOption(queuedump);
228            adminOptions.addOptionGroup(group);
229            addAuthOptions(adminOptions);
230            return adminOptions;
231        }
232    
233        /**
234         * Create option for command line option 'job'
235         * @return job options
236         */
237        protected Options createJobOptions() {
238            Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL");
239            Option config = new Option(CONFIG_OPTION, true, "job configuration file '.xml' or '.properties'");
240            Option submit = new Option(SUBMIT_OPTION, false, "submit a job");
241            Option run = new Option(RUN_OPTION, false, "run a job");
242            Option debug = new Option(DEBUG_OPTION, false, "Use debug mode to see debugging statements on stdout");
243            Option rerun = new Option(RERUN_OPTION, true,
244                    "rerun a job  (coordinator requires -action or -date, bundle requires -coordinator or -date)");
245            Option dryrun = new Option(DRYRUN_OPTION, false, "Dryrun a workflow (since 3.3.2) or coordinator (since 2.0) job without"
246                    + " actually executing it");
247            Option start = new Option(START_OPTION, true, "start a job");
248            Option suspend = new Option(SUSPEND_OPTION, true, "suspend a job");
249            Option resume = new Option(RESUME_OPTION, true, "resume a job");
250            Option kill = new Option(KILL_OPTION, true, "kill a job");
251            Option change = new Option(CHANGE_OPTION, true, "change a coordinator job");
252            Option changeValue = new Option(CHANGE_VALUE_OPTION, true,
253                    "new endtime/concurrency/pausetime value for changing a coordinator job");
254            Option info = new Option(INFO_OPTION, true, "info of a job");
255            Option offset = new Option(OFFSET_OPTION, true, "job info offset of actions (default '1', requires -info)");
256            Option len = new Option(LEN_OPTION, true, "number of actions (default TOTAL ACTIONS, requires -info)");
257            Option filter = new Option(FILTER_OPTION, true,
258                    "status=<S1>[;status=<S2>]* (All Coordinator actions satisfying any one of the status filters will be retreived. Currently, only supported for Coordinator job)");
259            Option localtime = new Option(LOCAL_TIME_OPTION, false, "use local time (same as passing your time zone to -" +
260                    TIME_ZONE_OPTION + "). Overrides -" + TIME_ZONE_OPTION + " option");
261            Option timezone = new Option(TIME_ZONE_OPTION, true,
262                    "use time zone with the specified ID (default GMT).\nSee 'oozie info -timezones' for a list");
263            Option log = new Option(LOG_OPTION, true, "job log");
264            Option definition = new Option(DEFINITION_OPTION, true, "job definition");
265            Option config_content = new Option(CONFIG_CONTENT_OPTION, true, "job configuration");
266            Option verbose = new Option(VERBOSE_OPTION, false, "verbose mode");
267            Option action = new Option(ACTION_OPTION, true,
268                    "coordinator rerun on action ids (requires -rerun); coordinator log retrieval on action ids (requires -log)");
269            Option date = new Option(DATE_OPTION, true,
270                    "coordinator/bundle rerun on action dates (requires -rerun); coordinator log retrieval on action dates (requires -log)");
271            Option rerun_coord = new Option(RERUN_COORD_OPTION, true, "bundle rerun on coordinator names (requires -rerun)");
272            Option rerun_refresh = new Option(RERUN_REFRESH_OPTION, false,
273                    "re-materialize the coordinator rerun actions (requires -rerun)");
274            Option rerun_nocleanup = new Option(RERUN_NOCLEANUP_OPTION, false,
275                    "do not clean up output-events of the coordiantor rerun actions (requires -rerun)");
276            Option property = OptionBuilder.withArgName("property=value").hasArgs(2).withValueSeparator().withDescription(
277                    "set/override value for given property").create("D");
278    
279            Option doAs = new Option(DO_AS_OPTION, true, "doAs user, impersonates as the specified user");
280    
281            OptionGroup actions = new OptionGroup();
282            actions.addOption(submit);
283            actions.addOption(start);
284            actions.addOption(run);
285            actions.addOption(dryrun);
286            actions.addOption(suspend);
287            actions.addOption(resume);
288            actions.addOption(kill);
289            actions.addOption(change);
290            actions.addOption(info);
291            actions.addOption(rerun);
292            actions.addOption(log);
293            actions.addOption(definition);
294            actions.addOption(config_content);
295            actions.setRequired(true);
296            Options jobOptions = new Options();
297            jobOptions.addOption(oozie);
298            jobOptions.addOption(doAs);
299            jobOptions.addOption(config);
300            jobOptions.addOption(property);
301            jobOptions.addOption(changeValue);
302            jobOptions.addOption(localtime);
303            jobOptions.addOption(timezone);
304            jobOptions.addOption(verbose);
305            jobOptions.addOption(debug);
306            jobOptions.addOption(offset);
307            jobOptions.addOption(len);
308            jobOptions.addOption(filter);
309            jobOptions.addOption(action);
310            jobOptions.addOption(date);
311            jobOptions.addOption(rerun_coord);
312            jobOptions.addOption(rerun_refresh);
313            jobOptions.addOption(rerun_nocleanup);
314            jobOptions.addOptionGroup(actions);
315            addAuthOptions(jobOptions);
316            return jobOptions;
317        }
318    
319        /**
320         * Create option for command line option 'jobs'
321         * @return jobs options
322         */
323        protected Options createJobsOptions() {
324            Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL");
325            Option start = new Option(OFFSET_OPTION, true, "jobs offset (default '1')");
326            Option jobtype = new Option(JOBTYPE_OPTION, true,
327                    "job type ('Supported in Oozie-2.0 or later versions ONLY - 'coordinator' or 'bundle' or 'wf'(default))");
328            Option len = new Option(LEN_OPTION, true, "number of jobs (default '100')");
329            Option filter = new Option(FILTER_OPTION, true, "user=<U>\\;name=<N>\\;group=<G>\\;status=<S>\\;frequency=<F>\\;unit=<M> " +
330                            "(Valid unit values are 'months', 'days', 'hours' or 'minutes'.)");
331            Option localtime = new Option(LOCAL_TIME_OPTION, false, "use local time (same as passing your time zone to -" +
332                    TIME_ZONE_OPTION + "). Overrides -" + TIME_ZONE_OPTION + " option");
333            Option timezone = new Option(TIME_ZONE_OPTION, true,
334                    "use time zone with the specified ID (default GMT).\nSee 'oozie info -timezones' for a list");
335            Option verbose = new Option(VERBOSE_OPTION, false, "verbose mode");
336            Option doAs = new Option(DO_AS_OPTION, true, "doAs user, impersonates as the specified user");
337            Option bulkMonitor = new Option(BULK_OPTION, true, "key-value pairs to filter bulk jobs response. e.g. bundle=<B>\\;" +
338                    "coordinators=<C>\\;actionstatus=<S>\\;startcreatedtime=<SC>\\;endcreatedtime=<EC>\\;" +
339                    "startscheduledtime=<SS>\\;endscheduledtime=<ES>\\; coordinators and actionstatus can be multiple comma separated values" +
340                    "bundle and coordinators are 'names' of those jobs. Bundle name is mandatory, other params are optional");
341            start.setType(Integer.class);
342            len.setType(Integer.class);
343            Options jobsOptions = new Options();
344            jobsOptions.addOption(oozie);
345            jobsOptions.addOption(doAs);
346            jobsOptions.addOption(localtime);
347            jobsOptions.addOption(timezone);
348            jobsOptions.addOption(start);
349            jobsOptions.addOption(len);
350            jobsOptions.addOption(oozie);
351            jobsOptions.addOption(filter);
352            jobsOptions.addOption(jobtype);
353            jobsOptions.addOption(verbose);
354            jobsOptions.addOption(bulkMonitor);
355            addAuthOptions(jobsOptions);
356            return jobsOptions;
357        }
358    
359        /**
360         * Create option for command line option 'sla'
361         *
362         * @return sla options
363         */
364        protected Options createSlaOptions() {
365            Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL");
366            Option start = new Option(OFFSET_OPTION, true, "start offset (default '0')");
367            Option len = new Option(LEN_OPTION, true, "number of results (default '100', max '1000')");
368            Option filter = new Option(FILTER_OPTION, true, "filter of SLA events");
369            start.setType(Integer.class);
370            len.setType(Integer.class);
371            Options slaOptions = new Options();
372            slaOptions.addOption(start);
373            slaOptions.addOption(len);
374            slaOptions.addOption(filter);
375            slaOptions.addOption(oozie);
376            addAuthOptions(slaOptions);
377            return slaOptions;
378        }
379    
380        /**
381         * Create option for command line option 'pig'
382         * @return pig options
383         */
384        @SuppressWarnings("static-access")
385        protected Options createPigOptions() {
386            Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL");
387            Option config = new Option(CONFIG_OPTION, true, "job configuration file '.properties'");
388            Option pigFile = new Option(PIGFILE_OPTION, true, "Pig script");
389            Option property = OptionBuilder.withArgName("property=value").hasArgs(2).withValueSeparator().withDescription(
390                    "set/override value for given property").create("D");
391            Option doAs = new Option(DO_AS_OPTION, true, "doAs user, impersonates as the specified user");
392            Options pigOptions = new Options();
393            pigOptions.addOption(oozie);
394            pigOptions.addOption(doAs);
395            pigOptions.addOption(config);
396            pigOptions.addOption(property);
397            pigOptions.addOption(pigFile);
398            addAuthOptions(pigOptions);
399            return pigOptions;
400        }
401    
402        /**
403         * Create option for command line option 'info'
404         * @return info options
405         */
406        protected Options createInfoOptions() {
407            Option timezones = new Option(INFO_TIME_ZONES_OPTION, false, "display a list of available time zones");
408            Options infoOptions = new Options();
409            infoOptions.addOption(timezones);
410            return infoOptions;
411        }
412    
413        /**
414         * Create option for command line option 'mapreduce'
415         * @return mapreduce options
416         */
417        @SuppressWarnings("static-access")
418        protected Options createMROptions() {
419            Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL");
420            Option config = new Option(CONFIG_OPTION, true, "job configuration file '.properties'");
421            Option property = OptionBuilder.withArgName("property=value").hasArgs(2).withValueSeparator().withDescription(
422                    "set/override value for given property").create("D");
423            Option doAs = new Option(DO_AS_OPTION, true, "doAs user, impersonates as the specified user");
424            Options mrOptions = new Options();
425            mrOptions.addOption(oozie);
426            mrOptions.addOption(doAs);
427            mrOptions.addOption(config);
428            mrOptions.addOption(property);
429            addAuthOptions(mrOptions);
430            return mrOptions;
431        }
432    
433        /**
434         * Run a CLI programmatically.
435         * <p/>
436         * It does not exit the JVM.
437         * <p/>
438         * A CLI instance can be used only once.
439         *
440         * @param args options and arguments for the Oozie CLI.
441         * @return '0' (success), '-1' (failure).
442         */
443        public synchronized int run(String[] args) {
444            if (used) {
445                throw new IllegalStateException("CLI instance already used");
446            }
447            used = true;
448    
449            final CLIParser parser = new CLIParser(OOZIE_OPTION, getCLIHelp());
450            parser.addCommand(HELP_CMD, "", "display usage for all commands or specified command", new Options(), false);
451            parser.addCommand(VERSION_CMD, "", "show client version", new Options(), false);
452            parser.addCommand(JOB_CMD, "", "job operations", createJobOptions(), false);
453            parser.addCommand(JOBS_CMD, "", "jobs status", createJobsOptions(), false);
454            parser.addCommand(ADMIN_CMD, "", "admin operations", createAdminOptions(), false);
455            parser.addCommand(VALIDATE_CMD, "", "validate a workflow XML file", new Options(), true);
456            parser.addCommand(SLA_CMD, "", "sla operations (Supported in Oozie-2.0 or later)", createSlaOptions(), false);
457            parser.addCommand(PIG_CMD, "-X ", "submit a pig job, everything after '-X' are pass-through parameters to pig",
458                    createPigOptions(), true);
459            parser.addCommand(INFO_CMD, "", "get more detailed info about specific topics", createInfoOptions(), false);
460            parser.addCommand(MR_CMD, "", "submit a mapreduce job", createMROptions(), false);
461    
462            try {
463                final CLIParser.Command command = parser.parse(args);
464    
465                String doAsUser = command.getCommandLine().getOptionValue(DO_AS_OPTION);
466    
467                if (doAsUser != null) {
468                    OozieClient.doAs(doAsUser, new Callable<Void>() {
469                        @Override
470                        public Void call() throws Exception {
471                            processCommand(parser, command);
472                            return null;
473                        }
474                    });
475                }
476                else {
477                    processCommand(parser, command);
478                }
479    
480                return 0;
481            }
482            catch (OozieCLIException ex) {
483                System.err.println("Error: " + ex.getMessage());
484                return -1;
485            }
486            catch (ParseException ex) {
487                System.err.println("Invalid sub-command: " + ex.getMessage());
488                System.err.println();
489                System.err.println(parser.shortHelp());
490                return -1;
491            }
492            catch (Exception ex) {
493                ex.printStackTrace();
494                System.err.println(ex.getMessage());
495                return -1;
496            }
497        }
498    
499        private void processCommand(CLIParser parser, CLIParser.Command command) throws Exception {
500            if (command.getName().equals(HELP_CMD)) {
501                parser.showHelp(command.getCommandLine());
502            }
503            else if (command.getName().equals(JOB_CMD)) {
504                jobCommand(command.getCommandLine());
505            }
506            else if (command.getName().equals(JOBS_CMD)) {
507                jobsCommand(command.getCommandLine());
508            }
509            else if (command.getName().equals(ADMIN_CMD)) {
510                adminCommand(command.getCommandLine());
511            }
512            else if (command.getName().equals(VERSION_CMD)) {
513                versionCommand();
514            }
515            else if (command.getName().equals(VALIDATE_CMD)) {
516                validateCommand(command.getCommandLine());
517            }
518            else if (command.getName().equals(SLA_CMD)) {
519                slaCommand(command.getCommandLine());
520            }
521            else if (command.getName().equals(PIG_CMD)) {
522                pigCommand(command.getCommandLine());
523            }
524            else if (command.getName().equals(INFO_CMD)) {
525                infoCommand(command.getCommandLine());
526            }
527            else if (command.getName().equals(MR_CMD)){
528                mrCommand(command.getCommandLine());
529            }
530        }
531        protected String getOozieUrl(CommandLine commandLine) {
532            String url = commandLine.getOptionValue(OOZIE_OPTION);
533            if (url == null) {
534                url = System.getenv(ENV_OOZIE_URL);
535                if (url == null) {
536                    throw new IllegalArgumentException(
537                            "Oozie URL is not available neither in command option or in the environment");
538                }
539            }
540            return url;
541        }
542    
543        private String getTimeZoneId(CommandLine commandLine)
544        {
545            if (commandLine.hasOption(LOCAL_TIME_OPTION)) {
546                return null;
547            }
548            if (commandLine.hasOption(TIME_ZONE_OPTION)) {
549                return commandLine.getOptionValue(TIME_ZONE_OPTION);
550            }
551            String timeZoneId = System.getenv(ENV_OOZIE_TIME_ZONE);
552            if (timeZoneId != null) {
553                return timeZoneId;
554            }
555            return "GMT";
556        }
557    
558        // Canibalized from Hadoop <code>Configuration.loadResource()</code>.
559        private Properties parse(InputStream is, Properties conf) throws IOException {
560            try {
561                DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
562                // ignore all comments inside the xml file
563                docBuilderFactory.setIgnoringComments(true);
564                DocumentBuilder builder = docBuilderFactory.newDocumentBuilder();
565                Document doc = builder.parse(is);
566                return parseDocument(doc, conf);
567            }
568            catch (SAXException e) {
569                throw new IOException(e);
570            }
571            catch (ParserConfigurationException e) {
572                throw new IOException(e);
573            }
574        }
575    
576        // Canibalized from Hadoop <code>Configuration.loadResource()</code>.
577        private Properties parseDocument(Document doc, Properties conf) throws IOException {
578            try {
579                Element root = doc.getDocumentElement();
580                if (!"configuration".equals(root.getTagName())) {
581                    throw new RuntimeException("bad conf file: top-level element not <configuration>");
582                }
583                NodeList props = root.getChildNodes();
584                for (int i = 0; i < props.getLength(); i++) {
585                    Node propNode = props.item(i);
586                    if (!(propNode instanceof Element)) {
587                        continue;
588                    }
589                    Element prop = (Element) propNode;
590                    if (!"property".equals(prop.getTagName())) {
591                        throw new RuntimeException("bad conf file: element not <property>");
592                    }
593                    NodeList fields = prop.getChildNodes();
594                    String attr = null;
595                    String value = null;
596                    for (int j = 0; j < fields.getLength(); j++) {
597                        Node fieldNode = fields.item(j);
598                        if (!(fieldNode instanceof Element)) {
599                            continue;
600                        }
601                        Element field = (Element) fieldNode;
602                        if ("name".equals(field.getTagName()) && field.hasChildNodes()) {
603                            attr = ((Text) field.getFirstChild()).getData();
604                        }
605                        if ("value".equals(field.getTagName()) && field.hasChildNodes()) {
606                            value = ((Text) field.getFirstChild()).getData();
607                        }
608                    }
609    
610                    if (attr != null && value != null) {
611                        conf.setProperty(attr, value);
612                    }
613                }
614                return conf;
615            }
616            catch (DOMException e) {
617                throw new IOException(e);
618            }
619        }
620    
621        private Properties getConfiguration(OozieClient wc, CommandLine commandLine) throws IOException {
622            Properties conf = wc.createConfiguration();
623            String configFile = commandLine.getOptionValue(CONFIG_OPTION);
624            if (configFile == null) {
625                throw new IOException("configuration file not specified");
626            }
627            else {
628                File file = new File(configFile);
629                if (!file.exists()) {
630                    throw new IOException("configuration file [" + configFile + "] not found");
631                }
632                if (configFile.endsWith(".properties")) {
633                    conf.load(new FileReader(file));
634                }
635                else if (configFile.endsWith(".xml")) {
636                    parse(new FileInputStream(configFile), conf);
637                }
638                else {
639                    throw new IllegalArgumentException("configuration must be a '.properties' or a '.xml' file");
640                }
641            }
642            if (commandLine.hasOption("D")) {
643                Properties commandLineProperties = commandLine.getOptionProperties("D");
644                conf.putAll(commandLineProperties);
645            }
646            return conf;
647        }
648    
649        /**
650         * @param commandLine command line string.
651         * @return change value specified by -value.
652         * @throws OozieCLIException
653         */
654        private String getChangeValue(CommandLine commandLine) throws OozieCLIException {
655            String changeValue = commandLine.getOptionValue(CHANGE_VALUE_OPTION);
656    
657            if (changeValue == null) {
658                throw new OozieCLIException("-value option needs to be specified for -change option");
659            }
660    
661            return changeValue;
662        }
663    
664        protected void addHeader(OozieClient wc) {
665            for (Map.Entry entry : System.getProperties().entrySet()) {
666                String key = (String) entry.getKey();
667                if (key.startsWith(WS_HEADER_PREFIX)) {
668                    String header = key.substring(WS_HEADER_PREFIX.length());
669                    wc.setHeader(header, (String) entry.getValue());
670                }
671            }
672        }
673    
674        /**
675         * Get auth option from command line
676         *
677         * @param commandLine the command line object
678         * @return auth option
679         */
680        protected String getAuthOption(CommandLine commandLine) {
681            String authOpt = commandLine.getOptionValue(AUTH_OPTION);
682            return authOpt;
683        }
684    
685        /**
686         * Create a OozieClient.
687         * <p/>
688         * It injects any '-Dheader:' as header to the the {@link org.apache.oozie.client.OozieClient}.
689         *
690         * @param commandLine the parsed command line options.
691         * @return a pre configured eXtended workflow client.
692         * @throws OozieCLIException thrown if the OozieClient could not be configured.
693         */
694        protected OozieClient createOozieClient(CommandLine commandLine) throws OozieCLIException {
695            return createXOozieClient(commandLine);
696        }
697    
698        /**
699         * Create a XOozieClient.
700         * <p/>
701         * It injects any '-Dheader:' as header to the the {@link org.apache.oozie.client.OozieClient}.
702         *
703         * @param commandLine the parsed command line options.
704         * @return a pre configured eXtended workflow client.
705         * @throws OozieCLIException thrown if the XOozieClient could not be configured.
706         */
707        protected XOozieClient createXOozieClient(CommandLine commandLine) throws OozieCLIException {
708            XOozieClient wc = new AuthOozieClient(getOozieUrl(commandLine), getAuthOption(commandLine));
709            addHeader(wc);
710            setDebugMode(wc,commandLine.hasOption(DEBUG_OPTION));
711            return wc;
712        }
713    
714        protected void setDebugMode(OozieClient wc, boolean debugOpt) {
715    
716            String debug = System.getenv(ENV_OOZIE_DEBUG);
717            if (debug != null && !debug.isEmpty()) {
718                int debugVal = 0;
719                try {
720                    debugVal = Integer.parseInt(debug.trim());
721                }
722                catch (Exception ex) {
723                    System.out.println("Unable to parse the debug settings. May be not an integer [" + debug + "]");
724                    ex.printStackTrace();
725                }
726                wc.setDebugMode(debugVal);
727            }
728            else if(debugOpt){  // CLI argument "-debug" used
729                wc.setDebugMode(1);
730            }
731        }
732    
733        private static String JOB_ID_PREFIX = "job: ";
734    
735        private void jobCommand(CommandLine commandLine) throws IOException, OozieCLIException {
736            XOozieClient wc = createXOozieClient(commandLine);
737    
738            List<String> options = new ArrayList<String>();
739            for (Option option : commandLine.getOptions()) {
740                options.add(option.getOpt());
741            }
742    
743            try {
744                if (options.contains(SUBMIT_OPTION)) {
745                    System.out.println(JOB_ID_PREFIX + wc.submit(getConfiguration(wc, commandLine)));
746                }
747                else if (options.contains(START_OPTION)) {
748                    wc.start(commandLine.getOptionValue(START_OPTION));
749                }
750                else if (options.contains(DRYRUN_OPTION)) {
751                    String dryrunStr = wc.dryrun(getConfiguration(wc, commandLine));
752                    if (dryrunStr.equals("OK")) {  // workflow
753                        System.out.println("OK");
754                    } else {                        // coordinator
755                        String[] dryrunStrs = dryrunStr.split("action for new instance");
756                        int arraysize = dryrunStrs.length;
757                        System.out.println("***coordJob after parsing: ***");
758                        System.out.println(dryrunStrs[0]);
759                        int aLen = dryrunStrs.length - 1;
760                        if (aLen < 0) {
761                            aLen = 0;
762                        }
763                        System.out.println("***total coord actions is " + aLen + " ***");
764                        for (int i = 1; i <= arraysize - 1; i++) {
765                            System.out.println(RULER);
766                            System.out.println("coordAction instance: " + i + ":");
767                            System.out.println(dryrunStrs[i]);
768                        }
769                    }
770                }
771                else if (options.contains(SUSPEND_OPTION)) {
772                    wc.suspend(commandLine.getOptionValue(SUSPEND_OPTION));
773                }
774                else if (options.contains(RESUME_OPTION)) {
775                    wc.resume(commandLine.getOptionValue(RESUME_OPTION));
776                }
777                else if (options.contains(KILL_OPTION)) {
778                    wc.kill(commandLine.getOptionValue(KILL_OPTION));
779                }
780                else if (options.contains(CHANGE_OPTION)) {
781                    wc.change(commandLine.getOptionValue(CHANGE_OPTION), getChangeValue(commandLine));
782                }
783                else if (options.contains(RUN_OPTION)) {
784                    System.out.println(JOB_ID_PREFIX + wc.run(getConfiguration(wc, commandLine)));
785                }
786                else if (options.contains(RERUN_OPTION)) {
787                    if (commandLine.getOptionValue(RERUN_OPTION).contains("-W")) {
788                        wc.reRun(commandLine.getOptionValue(RERUN_OPTION), getConfiguration(wc, commandLine));
789                    }
790                    else if (commandLine.getOptionValue(RERUN_OPTION).contains("-B")) {
791                        String bundleJobId = commandLine.getOptionValue(RERUN_OPTION);
792                        String coordScope = null;
793                        String dateScope = null;
794                        boolean refresh = false;
795                        boolean noCleanup = false;
796                        if (options.contains(ACTION_OPTION)) {
797                            throw new OozieCLIException("Invalid options provided for bundle rerun. " + ACTION_OPTION
798                                    + " is not valid for bundle rerun");
799                        }
800                        if (options.contains(DATE_OPTION)) {
801                            dateScope = commandLine.getOptionValue(DATE_OPTION);
802                        }
803    
804                        if (options.contains(RERUN_COORD_OPTION)) {
805                            coordScope = commandLine.getOptionValue(RERUN_COORD_OPTION);
806                        }
807    
808                        if (options.contains(RERUN_REFRESH_OPTION)) {
809                            refresh = true;
810                        }
811                        if (options.contains(RERUN_NOCLEANUP_OPTION)) {
812                            noCleanup = true;
813                        }
814                        wc.reRunBundle(bundleJobId, coordScope, dateScope, refresh, noCleanup);
815                        if (coordScope != null && !coordScope.isEmpty()) {
816                            System.out.println("Coordinators [" + coordScope + "] of bundle " + bundleJobId
817                                    + " are scheduled to rerun on date ranges [" + dateScope + "].");
818                        }
819                        else {
820                            System.out.println("All coordinators of bundle " + bundleJobId
821                                    + " are scheduled to rerun on the date ranges [" + dateScope + "].");
822                        }
823                    }
824                    else {
825                        String coordJobId = commandLine.getOptionValue(RERUN_OPTION);
826                        String scope = null;
827                        String rerunType = null;
828                        boolean refresh = false;
829                        boolean noCleanup = false;
830                        if (options.contains(DATE_OPTION) && options.contains(ACTION_OPTION)) {
831                            throw new OozieCLIException("Invalid options provided for rerun: either" + DATE_OPTION + " or "
832                                    + ACTION_OPTION + " expected. Don't use both at the same time.");
833                        }
834                        if (options.contains(DATE_OPTION)) {
835                            rerunType = RestConstants.JOB_COORD_RERUN_DATE;
836                            scope = commandLine.getOptionValue(DATE_OPTION);
837                        }
838                        else if (options.contains(ACTION_OPTION)) {
839                            rerunType = RestConstants.JOB_COORD_RERUN_ACTION;
840                            scope = commandLine.getOptionValue(ACTION_OPTION);
841                        }
842                        else {
843                            throw new OozieCLIException("Invalid options provided for rerun: " + DATE_OPTION + " or "
844                                    + ACTION_OPTION + " expected.");
845                        }
846                        if (options.contains(RERUN_REFRESH_OPTION)) {
847                            refresh = true;
848                        }
849                        if (options.contains(RERUN_NOCLEANUP_OPTION)) {
850                            noCleanup = true;
851                        }
852                        printRerunCoordActions(wc.reRunCoord(coordJobId, rerunType, scope, refresh, noCleanup));
853                    }
854                }
855                else if (options.contains(INFO_OPTION)) {
856                    String timeZoneId = getTimeZoneId(commandLine);
857                    if (commandLine.getOptionValue(INFO_OPTION).endsWith("-B")) {
858                        String filter = commandLine.getOptionValue(FILTER_OPTION);
859                        if (filter != null) {
860                            throw new OozieCLIException("Filter option is currently not supported for a Bundle job");
861                        }
862                        printBundleJob(wc.getBundleJobInfo(commandLine.getOptionValue(INFO_OPTION)), timeZoneId,
863                                options.contains(VERBOSE_OPTION));
864                    }
865                    else if (commandLine.getOptionValue(INFO_OPTION).endsWith("-C")) {
866                        String s = commandLine.getOptionValue(OFFSET_OPTION);
867                        int start = Integer.parseInt((s != null) ? s : "0");
868                        s = commandLine.getOptionValue(LEN_OPTION);
869                        int len = Integer.parseInt((s != null) ? s : "0");
870                        String filter = commandLine.getOptionValue(FILTER_OPTION);
871                        printCoordJob(wc.getCoordJobInfo(commandLine.getOptionValue(INFO_OPTION), filter, start, len), timeZoneId,
872                                options.contains(VERBOSE_OPTION));
873                    }
874                    else if (commandLine.getOptionValue(INFO_OPTION).contains("-C@")) {
875                        String filter = commandLine.getOptionValue(FILTER_OPTION);
876                        if (filter != null) {
877                            throw new OozieCLIException("Filter option is not supported for a Coordinator action");
878                        }
879                        printCoordAction(wc.getCoordActionInfo(commandLine.getOptionValue(INFO_OPTION)), timeZoneId);
880                    }
881                    else if (commandLine.getOptionValue(INFO_OPTION).contains("-W@")) {
882                        String filter = commandLine.getOptionValue(FILTER_OPTION);
883                        if (filter != null) {
884                            throw new OozieCLIException("Filter option is not supported for a Workflow action");
885                        }
886                        printWorkflowAction(wc.getWorkflowActionInfo(commandLine.getOptionValue(INFO_OPTION)), timeZoneId,
887                                options.contains(VERBOSE_OPTION));
888                    }
889                    else {
890                        String filter = commandLine.getOptionValue(FILTER_OPTION);
891                        if (filter != null) {
892                            throw new OozieCLIException("Filter option is currently not supported for a Workflow job");
893                        }
894                        String s = commandLine.getOptionValue(OFFSET_OPTION);
895                        int start = Integer.parseInt((s != null) ? s : "0");
896                        s = commandLine.getOptionValue(LEN_OPTION);
897                        String jobtype = commandLine.getOptionValue(JOBTYPE_OPTION);
898                        jobtype = (jobtype != null) ? jobtype : "wf";
899                        int len = Integer.parseInt((s != null) ? s : "0");
900                        printJob(wc.getJobInfo(commandLine.getOptionValue(INFO_OPTION), start, len), timeZoneId,
901                                options.contains(VERBOSE_OPTION));
902                    }
903                }
904                else if (options.contains(LOG_OPTION)) {
905                    PrintStream ps = System.out;
906                    if (commandLine.getOptionValue(LOG_OPTION).contains("-C")) {
907                        String logRetrievalScope = null;
908                        String logRetrievalType = null;
909                        if (options.contains(ACTION_OPTION)) {
910                            logRetrievalType = RestConstants.JOB_LOG_ACTION;
911                            logRetrievalScope = commandLine.getOptionValue(ACTION_OPTION);
912                        }
913                        if (options.contains(DATE_OPTION)) {
914                            logRetrievalType = RestConstants.JOB_LOG_DATE;
915                            logRetrievalScope = commandLine.getOptionValue(DATE_OPTION);
916                        }
917                        try {
918                            wc.getJobLog(commandLine.getOptionValue(LOG_OPTION), logRetrievalType, logRetrievalScope, ps);
919                        }
920                        finally {
921                            ps.close();
922                        }
923                    }
924                    else {
925                        if (!options.contains(ACTION_OPTION) && !options.contains(DATE_OPTION)) {
926                            wc.getJobLog(commandLine.getOptionValue(LOG_OPTION), null, null, ps);
927                        }
928                        else {
929                            throw new OozieCLIException("Invalid options provided for log retrieval. " + ACTION_OPTION
930                                    + " and " + DATE_OPTION + " are valid only for coordinator job log retrieval");
931                        }
932                    }
933                }
934                else if (options.contains(DEFINITION_OPTION)) {
935                    System.out.println(wc.getJobDefinition(commandLine.getOptionValue(DEFINITION_OPTION)));
936                }
937                else if (options.contains(CONFIG_CONTENT_OPTION)) {
938                    if (commandLine.getOptionValue(CONFIG_CONTENT_OPTION).endsWith("-C")) {
939                        System.out.println(wc.getCoordJobInfo(commandLine.getOptionValue(CONFIG_CONTENT_OPTION)).getConf());
940                    }
941                    else if (commandLine.getOptionValue(CONFIG_CONTENT_OPTION).endsWith("-W")) {
942                        System.out.println(wc.getJobInfo(commandLine.getOptionValue(CONFIG_CONTENT_OPTION)).getConf());
943                    }
944                    else if (commandLine.getOptionValue(CONFIG_CONTENT_OPTION).endsWith("-B")) {
945                        System.out
946                                .println(wc.getBundleJobInfo(commandLine.getOptionValue(CONFIG_CONTENT_OPTION)).getConf());
947                    }
948                    else {
949                        System.out.println("ERROR:  job id [" + commandLine.getOptionValue(CONFIG_CONTENT_OPTION)
950                                + "] doesn't end with either C or W or B");
951                    }
952                }
953            }
954            catch (OozieClientException ex) {
955                throw new OozieCLIException(ex.toString(), ex);
956            }
957        }
958    
959        private void printCoordJob(CoordinatorJob coordJob, String timeZoneId, boolean verbose) {
960            System.out.println("Job ID : " + coordJob.getId());
961    
962            System.out.println(RULER);
963    
964            List<CoordinatorAction> actions = coordJob.getActions();
965            System.out.println("Job Name    : " + maskIfNull(coordJob.getAppName()));
966            System.out.println("App Path    : " + maskIfNull(coordJob.getAppPath()));
967            System.out.println("Status      : " + coordJob.getStatus());
968            System.out.println("Start Time  : " + maskDate(coordJob.getStartTime(), timeZoneId, false));
969            System.out.println("End Time    : " + maskDate(coordJob.getEndTime(), timeZoneId, false));
970            System.out.println("Pause Time  : " + maskDate(coordJob.getPauseTime(), timeZoneId, false));
971            System.out.println("Concurrency : " + coordJob.getConcurrency());
972            System.out.println(RULER);
973    
974            if (verbose) {
975                System.out.println("ID" + VERBOSE_DELIMITER + "Action Number" + VERBOSE_DELIMITER + "Console URL"
976                        + VERBOSE_DELIMITER + "Error Code" + VERBOSE_DELIMITER + "Error Message" + VERBOSE_DELIMITER
977                        + "External ID" + VERBOSE_DELIMITER + "External Status" + VERBOSE_DELIMITER + "Job ID"
978                        + VERBOSE_DELIMITER + "Tracker URI" + VERBOSE_DELIMITER + "Created" + VERBOSE_DELIMITER
979                        + "Nominal Time" + VERBOSE_DELIMITER + "Status" + VERBOSE_DELIMITER + "Last Modified"
980                        + VERBOSE_DELIMITER + "Missing Dependencies");
981                System.out.println(RULER);
982    
983                for (CoordinatorAction action : actions) {
984                    String missingDep = action.getMissingDependencies();
985                    if(missingDep != null && !missingDep.isEmpty()) {
986                        missingDep = missingDep.split(INSTANCE_SEPARATOR)[0];
987                    }
988                    System.out.println(maskIfNull(action.getId()) + VERBOSE_DELIMITER + action.getActionNumber()
989                            + VERBOSE_DELIMITER + maskIfNull(action.getConsoleUrl()) + VERBOSE_DELIMITER
990                            + maskIfNull(action.getErrorCode()) + VERBOSE_DELIMITER + maskIfNull(action.getErrorMessage())
991                            + VERBOSE_DELIMITER + maskIfNull(action.getExternalId()) + VERBOSE_DELIMITER
992                            + maskIfNull(action.getExternalStatus()) + VERBOSE_DELIMITER + maskIfNull(action.getJobId())
993                            + VERBOSE_DELIMITER + maskIfNull(action.getTrackerUri()) + VERBOSE_DELIMITER
994                            + maskDate(action.getCreatedTime(), timeZoneId, verbose) + VERBOSE_DELIMITER
995                            + maskDate(action.getNominalTime(), timeZoneId, verbose) + action.getStatus() + VERBOSE_DELIMITER
996                            + maskDate(action.getLastModifiedTime(), timeZoneId, verbose) + VERBOSE_DELIMITER
997                            + maskIfNull(missingDep));
998    
999                    System.out.println(RULER);
1000                }
1001            }
1002            else {
1003                System.out.println(String.format(COORD_ACTION_FORMATTER, "ID", "Status", "Ext ID", "Err Code", "Created",
1004                        "Nominal Time", "Last Mod"));
1005    
1006                for (CoordinatorAction action : actions) {
1007                    System.out.println(String.format(COORD_ACTION_FORMATTER, maskIfNull(action.getId()),
1008                            action.getStatus(), maskIfNull(action.getExternalId()), maskIfNull(action.getErrorCode()),
1009                            maskDate(action.getCreatedTime(), timeZoneId, verbose), maskDate(action.getNominalTime(), timeZoneId, verbose),
1010                            maskDate(action.getLastModifiedTime(), timeZoneId, verbose)));
1011    
1012                    System.out.println(RULER);
1013                }
1014            }
1015        }
1016    
1017        private void printBundleJob(BundleJob bundleJob, String timeZoneId, boolean verbose) {
1018            System.out.println("Job ID : " + bundleJob.getId());
1019    
1020            System.out.println(RULER);
1021    
1022            List<CoordinatorJob> coordinators = bundleJob.getCoordinators();
1023            System.out.println("Job Name : " + maskIfNull(bundleJob.getAppName()));
1024            System.out.println("App Path : " + maskIfNull(bundleJob.getAppPath()));
1025            System.out.println("Status   : " + bundleJob.getStatus());
1026            System.out.println("Kickoff time   : " + bundleJob.getKickoffTime());
1027            System.out.println(RULER);
1028    
1029            System.out.println(String.format(BUNDLE_COORD_JOBS_FORMATTER, "Job ID", "Status", "Freq", "Unit", "Started",
1030                    "Next Materialized"));
1031            System.out.println(RULER);
1032    
1033            for (CoordinatorJob job : coordinators) {
1034                System.out.println(String.format(BUNDLE_COORD_JOBS_FORMATTER, maskIfNull(job.getId()), job.getStatus(),
1035                        job.getFrequency(), job.getTimeUnit(), maskDate(job.getStartTime(), timeZoneId, verbose),
1036                        maskDate(job.getNextMaterializedTime(), timeZoneId, verbose)));
1037    
1038                System.out.println(RULER);
1039            }
1040        }
1041    
1042        private void printCoordAction(CoordinatorAction coordAction, String timeZoneId) {
1043            System.out.println("ID : " + maskIfNull(coordAction.getId()));
1044    
1045            System.out.println(RULER);
1046    
1047            System.out.println("Action Number        : " + coordAction.getActionNumber());
1048            System.out.println("Console URL          : " + maskIfNull(coordAction.getConsoleUrl()));
1049            System.out.println("Error Code           : " + maskIfNull(coordAction.getErrorCode()));
1050            System.out.println("Error Message        : " + maskIfNull(coordAction.getErrorMessage()));
1051            System.out.println("External ID          : " + maskIfNull(coordAction.getExternalId()));
1052            System.out.println("External Status      : " + maskIfNull(coordAction.getExternalStatus()));
1053            System.out.println("Job ID               : " + maskIfNull(coordAction.getJobId()));
1054            System.out.println("Tracker URI          : " + maskIfNull(coordAction.getTrackerUri()));
1055            System.out.println("Created              : " + maskDate(coordAction.getCreatedTime(), timeZoneId, false));
1056            System.out.println("Nominal Time         : " + maskDate(coordAction.getNominalTime(), timeZoneId, false));
1057            System.out.println("Status               : " + coordAction.getStatus());
1058            System.out.println("Last Modified        : " + maskDate(coordAction.getLastModifiedTime(), timeZoneId, false));
1059            String missingDep = coordAction.getMissingDependencies();
1060            if(missingDep != null && !missingDep.isEmpty()) {
1061                missingDep = missingDep.split(INSTANCE_SEPARATOR)[0];
1062            }
1063            System.out.println("First Missing Dependency : " + maskIfNull(missingDep));
1064    
1065            System.out.println(RULER);
1066        }
1067    
1068        private void printRerunCoordActions(List<CoordinatorAction> actions) {
1069            if (actions != null && actions.size() > 0) {
1070                System.out.println("Action ID" + VERBOSE_DELIMITER + "Nominal Time");
1071                System.out.println(RULER);
1072                for (CoordinatorAction action : actions) {
1073                    System.out.println(maskIfNull(action.getId()) + VERBOSE_DELIMITER
1074                            + maskDate(action.getNominalTime(), null,false));
1075                }
1076            }
1077            else {
1078                System.out.println("No Actions match your rerun criteria!");
1079            }
1080        }
1081    
1082        private void printWorkflowAction(WorkflowAction action, String timeZoneId, boolean verbose) {
1083            System.out.println("ID : " + maskIfNull(action.getId()));
1084    
1085            System.out.println(RULER);
1086    
1087            System.out.println("Console URL       : " + maskIfNull(action.getConsoleUrl()));
1088            System.out.println("Error Code        : " + maskIfNull(action.getErrorCode()));
1089            System.out.println("Error Message     : " + maskIfNull(action.getErrorMessage()));
1090            System.out.println("External ID       : " + maskIfNull(action.getExternalId()));
1091            System.out.println("External Status   : " + maskIfNull(action.getExternalStatus()));
1092            System.out.println("Name              : " + maskIfNull(action.getName()));
1093            System.out.println("Retries           : " + action.getRetries());
1094            System.out.println("Tracker URI       : " + maskIfNull(action.getTrackerUri()));
1095            System.out.println("Type              : " + maskIfNull(action.getType()));
1096            System.out.println("Started           : " + maskDate(action.getStartTime(), timeZoneId, verbose));
1097            System.out.println("Status            : " + action.getStatus());
1098            System.out.println("Ended             : " + maskDate(action.getEndTime(), timeZoneId, verbose));
1099    
1100            if (verbose) {
1101                System.out.println("External Stats    : " + action.getStats());
1102                System.out.println("External ChildIDs : " + action.getExternalChildIDs());
1103            }
1104    
1105            System.out.println(RULER);
1106        }
1107    
1108        private static final String WORKFLOW_JOBS_FORMATTER = "%-41s%-13s%-10s%-10s%-10s%-24s%-24s";
1109        private static final String COORD_JOBS_FORMATTER = "%-41s%-15s%-10s%-5s%-13s%-24s%-24s";
1110        private static final String BUNDLE_JOBS_FORMATTER = "%-41s%-15s%-10s%-20s%-20s%-13s%-13s";
1111        private static final String BUNDLE_COORD_JOBS_FORMATTER = "%-41s%-10s%-5s%-13s%-24s%-24s";
1112    
1113        private static final String WORKFLOW_ACTION_FORMATTER = "%-78s%-10s%-23s%-11s%-10s";
1114        private static final String COORD_ACTION_FORMATTER = "%-43s%-10s%-37s%-10s%-21s%-21s";
1115        private static final String BULK_RESPONSE_FORMATTER = "%-41s%-41s%-37s%-37s%-13s%-21s%-24s";
1116    
1117        private void printJob(WorkflowJob job, String timeZoneId, boolean verbose) throws IOException {
1118            System.out.println("Job ID : " + maskIfNull(job.getId()));
1119    
1120            System.out.println(RULER);
1121    
1122            System.out.println("Workflow Name : " + maskIfNull(job.getAppName()));
1123            System.out.println("App Path      : " + maskIfNull(job.getAppPath()));
1124            System.out.println("Status        : " + job.getStatus());
1125            System.out.println("Run           : " + job.getRun());
1126            System.out.println("User          : " + maskIfNull(job.getUser()));
1127            System.out.println("Group         : " + maskIfNull(job.getGroup()));
1128            System.out.println("Created       : " + maskDate(job.getCreatedTime(), timeZoneId, verbose));
1129            System.out.println("Started       : " + maskDate(job.getStartTime(), timeZoneId, verbose));
1130            System.out.println("Last Modified : " + maskDate(job.getLastModifiedTime(), timeZoneId, verbose));
1131            System.out.println("Ended         : " + maskDate(job.getEndTime(), timeZoneId, verbose));
1132            System.out.println("CoordAction ID: " + maskIfNull(job.getParentId()));
1133    
1134            List<WorkflowAction> actions = job.getActions();
1135    
1136            if (actions != null && actions.size() > 0) {
1137                System.out.println();
1138                System.out.println("Actions");
1139                System.out.println(RULER);
1140    
1141                if (verbose) {
1142                    System.out.println("ID" + VERBOSE_DELIMITER + "Console URL" + VERBOSE_DELIMITER + "Error Code"
1143                            + VERBOSE_DELIMITER + "Error Message" + VERBOSE_DELIMITER + "External ID" + VERBOSE_DELIMITER
1144                            + "External Status" + VERBOSE_DELIMITER + "Name" + VERBOSE_DELIMITER + "Retries"
1145                            + VERBOSE_DELIMITER + "Tracker URI" + VERBOSE_DELIMITER + "Type" + VERBOSE_DELIMITER
1146                            + "Started" + VERBOSE_DELIMITER + "Status" + VERBOSE_DELIMITER + "Ended");
1147                    System.out.println(RULER);
1148    
1149                    for (WorkflowAction action : job.getActions()) {
1150                        System.out.println(maskIfNull(action.getId()) + VERBOSE_DELIMITER
1151                                + maskIfNull(action.getConsoleUrl()) + VERBOSE_DELIMITER
1152                                + maskIfNull(action.getErrorCode()) + VERBOSE_DELIMITER
1153                                + maskIfNull(action.getErrorMessage()) + VERBOSE_DELIMITER
1154                                + maskIfNull(action.getExternalId()) + VERBOSE_DELIMITER
1155                                + maskIfNull(action.getExternalStatus()) + VERBOSE_DELIMITER + maskIfNull(action.getName())
1156                                + VERBOSE_DELIMITER + action.getRetries() + VERBOSE_DELIMITER
1157                                + maskIfNull(action.getTrackerUri()) + VERBOSE_DELIMITER + maskIfNull(action.getType())
1158                                + VERBOSE_DELIMITER + maskDate(action.getStartTime(), timeZoneId, verbose)
1159                                + VERBOSE_DELIMITER + action.getStatus() + VERBOSE_DELIMITER
1160                                + maskDate(action.getEndTime(), timeZoneId, verbose));
1161    
1162                        System.out.println(RULER);
1163                    }
1164                }
1165                else {
1166                    System.out.println(String.format(WORKFLOW_ACTION_FORMATTER, "ID", "Status", "Ext ID", "Ext Status",
1167                            "Err Code"));
1168    
1169                    System.out.println(RULER);
1170    
1171                    for (WorkflowAction action : job.getActions()) {
1172                        System.out.println(String.format(WORKFLOW_ACTION_FORMATTER, maskIfNull(action.getId()), action
1173                                .getStatus(), maskIfNull(action.getExternalId()), maskIfNull(action.getExternalStatus()),
1174                                maskIfNull(action.getErrorCode())));
1175    
1176                        System.out.println(RULER);
1177                    }
1178                }
1179            }
1180            else {
1181                System.out.println(RULER);
1182            }
1183    
1184            System.out.println();
1185        }
1186    
1187        private void jobsCommand(CommandLine commandLine) throws IOException, OozieCLIException {
1188            XOozieClient wc = createXOozieClient(commandLine);
1189    
1190            String filter = commandLine.getOptionValue(FILTER_OPTION);
1191            String s = commandLine.getOptionValue(OFFSET_OPTION);
1192            int start = Integer.parseInt((s != null) ? s : "0");
1193            s = commandLine.getOptionValue(LEN_OPTION);
1194            String jobtype = commandLine.getOptionValue(JOBTYPE_OPTION);
1195            String timeZoneId = getTimeZoneId(commandLine);
1196            jobtype = (jobtype != null) ? jobtype : "wf";
1197            int len = Integer.parseInt((s != null) ? s : "0");
1198            String bulkFilterString = commandLine.getOptionValue(BULK_OPTION);
1199    
1200            try {
1201                if (bulkFilterString != null) {
1202                    printBulkJobs(wc.getBulkInfo(bulkFilterString, start, len), timeZoneId);
1203                }
1204                else if (jobtype.toLowerCase().contains("wf")) {
1205                    printJobs(wc.getJobsInfo(filter, start, len), timeZoneId, commandLine.hasOption(VERBOSE_OPTION));
1206                }
1207                else if (jobtype.toLowerCase().startsWith("coord")) {
1208                    printCoordJobs(wc.getCoordJobsInfo(filter, start, len), timeZoneId, commandLine.hasOption(VERBOSE_OPTION));
1209                }
1210                else if (jobtype.toLowerCase().startsWith("bundle")) {
1211                    printBundleJobs(wc.getBundleJobsInfo(filter, start, len), timeZoneId, commandLine.hasOption(VERBOSE_OPTION));
1212                }
1213    
1214            }
1215            catch (OozieClientException ex) {
1216                throw new OozieCLIException(ex.toString(), ex);
1217            }
1218        }
1219    
1220        private void printCoordJobs(List<CoordinatorJob> jobs, String timeZoneId, boolean verbose) throws IOException {
1221            if (jobs != null && jobs.size() > 0) {
1222                if (verbose) {
1223                    System.out.println("Job ID" + VERBOSE_DELIMITER + "App Name" + VERBOSE_DELIMITER + "App Path"
1224                            + VERBOSE_DELIMITER + "Console URL" + VERBOSE_DELIMITER + "User" + VERBOSE_DELIMITER + "Group"
1225                            + VERBOSE_DELIMITER + "Concurrency" + VERBOSE_DELIMITER + "Frequency" + VERBOSE_DELIMITER
1226                            + "Time Unit" + VERBOSE_DELIMITER + "Time Zone" + VERBOSE_DELIMITER + "Time Out"
1227                            + VERBOSE_DELIMITER + "Started" + VERBOSE_DELIMITER + "Next Materialize" + VERBOSE_DELIMITER
1228                            + "Status" + VERBOSE_DELIMITER + "Last Action" + VERBOSE_DELIMITER + "Ended");
1229                    System.out.println(RULER);
1230    
1231                    for (CoordinatorJob job : jobs) {
1232                        System.out.println(maskIfNull(job.getId()) + VERBOSE_DELIMITER + maskIfNull(job.getAppName())
1233                                + VERBOSE_DELIMITER + maskIfNull(job.getAppPath()) + VERBOSE_DELIMITER
1234                                + maskIfNull(job.getConsoleUrl()) + VERBOSE_DELIMITER + maskIfNull(job.getUser())
1235                                + VERBOSE_DELIMITER + maskIfNull(job.getGroup()) + VERBOSE_DELIMITER + job.getConcurrency()
1236                                + VERBOSE_DELIMITER + job.getFrequency() + VERBOSE_DELIMITER + job.getTimeUnit()
1237                                + VERBOSE_DELIMITER + maskIfNull(job.getTimeZone()) + VERBOSE_DELIMITER + job.getTimeout()
1238                                + VERBOSE_DELIMITER + maskDate(job.getStartTime(), timeZoneId, verbose) + VERBOSE_DELIMITER
1239                                + maskDate(job.getNextMaterializedTime(), timeZoneId, verbose) + VERBOSE_DELIMITER
1240                                + job.getStatus() + VERBOSE_DELIMITER
1241                                + maskDate(job.getLastActionTime(), timeZoneId, verbose) + VERBOSE_DELIMITER
1242                                + maskDate(job.getEndTime(), timeZoneId, verbose));
1243    
1244                        System.out.println(RULER);
1245                    }
1246                }
1247                else {
1248                    System.out.println(String.format(COORD_JOBS_FORMATTER, "Job ID", "App Name", "Status", "Freq", "Unit",
1249                            "Started", "Next Materialized"));
1250                    System.out.println(RULER);
1251    
1252                    for (CoordinatorJob job : jobs) {
1253                        System.out.println(String.format(COORD_JOBS_FORMATTER, maskIfNull(job.getId()), maskIfNull(job
1254                                .getAppName()), job.getStatus(), job.getFrequency(), job.getTimeUnit(), maskDate(job
1255                                .getStartTime(), timeZoneId, verbose), maskDate(job.getNextMaterializedTime(), timeZoneId, verbose)));
1256    
1257                        System.out.println(RULER);
1258                    }
1259                }
1260            }
1261            else {
1262                System.out.println("No Jobs match your criteria!");
1263            }
1264        }
1265    
1266        private void printBulkJobs(List<BulkResponse> jobs, String timeZoneId) throws IOException {
1267            if (jobs != null && jobs.size() > 0) {
1268                System.out.println(String.format(BULK_RESPONSE_FORMATTER, "Bundle Name", "Coordinator Name",
1269                        "Coord Action ID", "External ID", "Status", "Created Time", "Error Message"));
1270    
1271                for (BulkResponse response : jobs) {
1272                    System.out.println(String.format(BULK_RESPONSE_FORMATTER, maskIfNull((response.getBundle()).getAppName()),
1273                            maskIfNull((response.getCoordinator()).getAppName()), maskIfNull((response.getAction()).getId()),
1274                            maskIfNull((response.getAction()).getExternalId()), (response.getAction()).getStatus(),
1275                            maskDate((response.getAction()).getCreatedTime(), timeZoneId, false), (response.getAction()).getErrorMessage()));
1276                    System.out.println(RULER);
1277                }
1278            }
1279            else {
1280                System.out.println("Bulk request criteria did not match any coordinator actions");
1281            }
1282        }
1283    
1284        private void printBundleJobs(List<BundleJob> jobs, String timeZoneId, boolean verbose) throws IOException {
1285            if (jobs != null && jobs.size() > 0) {
1286                if (verbose) {
1287                    System.out.println("Job ID" + VERBOSE_DELIMITER + "Bundle Name" + VERBOSE_DELIMITER + "Bundle Path"
1288                            + VERBOSE_DELIMITER + "User" + VERBOSE_DELIMITER + "Group" + VERBOSE_DELIMITER + "Status"
1289                            + VERBOSE_DELIMITER + "Kickoff" + VERBOSE_DELIMITER + "Pause" + VERBOSE_DELIMITER + "Created"
1290                            + VERBOSE_DELIMITER + "Console URL");
1291                    System.out.println(RULER);
1292    
1293                    for (BundleJob job : jobs) {
1294                        System.out.println(maskIfNull(job.getId()) + VERBOSE_DELIMITER + maskIfNull(job.getAppName())
1295                                + VERBOSE_DELIMITER + maskIfNull(job.getAppPath()) + VERBOSE_DELIMITER
1296                                + maskIfNull(job.getUser()) + VERBOSE_DELIMITER + maskIfNull(job.getGroup())
1297                                + VERBOSE_DELIMITER + job.getStatus() + VERBOSE_DELIMITER
1298                                + maskDate(job.getKickoffTime(), timeZoneId, verbose) + VERBOSE_DELIMITER
1299                                + maskDate(job.getPauseTime(), timeZoneId, verbose) + VERBOSE_DELIMITER
1300                                + maskDate(job.getCreatedTime(), timeZoneId, verbose) + VERBOSE_DELIMITER
1301                                + maskIfNull(job.getConsoleUrl()));
1302    
1303                        System.out.println(RULER);
1304                    }
1305                }
1306                else {
1307                    System.out.println(String.format(BUNDLE_JOBS_FORMATTER, "Job ID", "Bundle Name", "Status", "Kickoff",
1308                            "Created", "User", "Group"));
1309                    System.out.println(RULER);
1310    
1311                    for (BundleJob job : jobs) {
1312                        System.out.println(String.format(BUNDLE_JOBS_FORMATTER, maskIfNull(job.getId()),
1313                                maskIfNull(job.getAppName()), job.getStatus(),
1314                                maskDate(job.getKickoffTime(), timeZoneId, verbose),
1315                                maskDate(job.getCreatedTime(), timeZoneId, verbose), maskIfNull(job.getUser()),
1316                                maskIfNull(job.getGroup())));
1317                        System.out.println(RULER);
1318                    }
1319                }
1320            }
1321            else {
1322                System.out.println("No Jobs match your criteria!");
1323            }
1324        }
1325    
1326        private void slaCommand(CommandLine commandLine) throws IOException, OozieCLIException {
1327            XOozieClient wc = createXOozieClient(commandLine);
1328            List<String> options = new ArrayList<String>();
1329            for (Option option : commandLine.getOptions()) {
1330                options.add(option.getOpt());
1331            }
1332    
1333            String s = commandLine.getOptionValue(OFFSET_OPTION);
1334            int start = Integer.parseInt((s != null) ? s : "0");
1335            s = commandLine.getOptionValue(LEN_OPTION);
1336            int len = Integer.parseInt((s != null) ? s : "100");
1337            String filter = commandLine.getOptionValue(FILTER_OPTION);
1338    
1339            try {
1340                wc.getSlaInfo(start, len, filter);
1341            }
1342            catch (OozieClientException ex) {
1343                throw new OozieCLIException(ex.toString(), ex);
1344            }
1345        }
1346    
1347        private void adminCommand(CommandLine commandLine) throws OozieCLIException {
1348            XOozieClient wc = createXOozieClient(commandLine);
1349    
1350            List<String> options = new ArrayList<String>();
1351            for (Option option : commandLine.getOptions()) {
1352                options.add(option.getOpt());
1353            }
1354    
1355            try {
1356                SYSTEM_MODE status = SYSTEM_MODE.NORMAL;
1357                if (options.contains(VERSION_OPTION)) {
1358                    System.out.println("Oozie server build version: " + wc.getServerBuildVersion());
1359                }
1360                else if (options.contains(SYSTEM_MODE_OPTION)) {
1361                    String systemModeOption = commandLine.getOptionValue(SYSTEM_MODE_OPTION).toUpperCase();
1362                    try {
1363                        status = SYSTEM_MODE.valueOf(systemModeOption);
1364                    }
1365                    catch (Exception e) {
1366                        throw new OozieCLIException("Invalid input provided for option: " + SYSTEM_MODE_OPTION
1367                                + " value given :" + systemModeOption
1368                                + " Expected values are: NORMAL/NOWEBSERVICE/SAFEMODE ");
1369                    }
1370                    wc.setSystemMode(status);
1371                    System.out.println("System mode: " + status);
1372                }
1373                else if (options.contains(STATUS_OPTION)) {
1374                    status = wc.getSystemMode();
1375                    System.out.println("System mode: " + status);
1376                }
1377                else if (options.contains(QUEUE_DUMP_OPTION)) {
1378    
1379                    List<String> list = wc.getQueueDump();
1380                    if (list != null && list.size() != 0) {
1381                        for (String str : list) {
1382                            System.out.println(str);
1383                        }
1384                    }
1385                    else {
1386                        System.out.println("QueueDump is null!");
1387                    }
1388                }
1389            }
1390            catch (OozieClientException ex) {
1391                throw new OozieCLIException(ex.toString(), ex);
1392            }
1393        }
1394    
1395        private void versionCommand() throws OozieCLIException {
1396            System.out.println("Oozie client build version: "
1397                    + BuildInfo.getBuildInfo().getProperty(BuildInfo.BUILD_VERSION));
1398        }
1399    
1400        private void printJobs(List<WorkflowJob> jobs, String timeZoneId, boolean verbose) throws IOException {
1401            if (jobs != null && jobs.size() > 0) {
1402                if (verbose) {
1403                    System.out.println("Job ID" + VERBOSE_DELIMITER + "App Name" + VERBOSE_DELIMITER + "App Path"
1404                            + VERBOSE_DELIMITER + "Console URL" + VERBOSE_DELIMITER + "User" + VERBOSE_DELIMITER + "Group"
1405                            + VERBOSE_DELIMITER + "Run" + VERBOSE_DELIMITER + "Created" + VERBOSE_DELIMITER + "Started"
1406                            + VERBOSE_DELIMITER + "Status" + VERBOSE_DELIMITER + "Last Modified" + VERBOSE_DELIMITER
1407                            + "Ended");
1408                    System.out.println(RULER);
1409    
1410                    for (WorkflowJob job : jobs) {
1411                        System.out.println(maskIfNull(job.getId()) + VERBOSE_DELIMITER + maskIfNull(job.getAppName())
1412                                + VERBOSE_DELIMITER + maskIfNull(job.getAppPath()) + VERBOSE_DELIMITER
1413                                + maskIfNull(job.getConsoleUrl()) + VERBOSE_DELIMITER + maskIfNull(job.getUser())
1414                                + VERBOSE_DELIMITER + maskIfNull(job.getGroup()) + VERBOSE_DELIMITER + job.getRun()
1415                                + VERBOSE_DELIMITER + maskDate(job.getCreatedTime(), timeZoneId, verbose)
1416                                + VERBOSE_DELIMITER + maskDate(job.getStartTime(), timeZoneId, verbose) + VERBOSE_DELIMITER
1417                                + job.getStatus() + VERBOSE_DELIMITER
1418                                + maskDate(job.getLastModifiedTime(), timeZoneId, verbose) + VERBOSE_DELIMITER
1419                                + maskDate(job.getEndTime(), timeZoneId, verbose));
1420    
1421                        System.out.println(RULER);
1422                    }
1423                }
1424                else {
1425                    System.out.println(String.format(WORKFLOW_JOBS_FORMATTER, "Job ID", "App Name", "Status", "User",
1426                            "Group", "Started", "Ended"));
1427                    System.out.println(RULER);
1428    
1429                    for (WorkflowJob job : jobs) {
1430                        System.out.println(String.format(WORKFLOW_JOBS_FORMATTER, maskIfNull(job.getId()),
1431                                maskIfNull(job.getAppName()), job.getStatus(), maskIfNull(job.getUser()),
1432                                maskIfNull(job.getGroup()), maskDate(job.getStartTime(), timeZoneId, verbose),
1433                                maskDate(job.getEndTime(), timeZoneId, verbose)));
1434    
1435                        System.out.println(RULER);
1436                    }
1437                }
1438            }
1439            else {
1440                System.out.println("No Jobs match your criteria!");
1441            }
1442        }
1443    
1444        private String maskIfNull(String value) {
1445            if (value != null && value.length() > 0) {
1446                return value;
1447            }
1448            return "-";
1449        }
1450    
1451        private String maskDate(Date date, String timeZoneId, boolean verbose) {
1452            if (date == null) {
1453                return "-";
1454            }
1455    
1456            SimpleDateFormat dateFormater = null;
1457            if (verbose) {
1458                dateFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzz", Locale.US);
1459            }
1460            else {
1461                dateFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm zzz", Locale.US);
1462            }
1463    
1464            if (timeZoneId != null) {
1465                dateFormater.setTimeZone(TimeZone.getTimeZone(timeZoneId));
1466            }
1467            String dateString = dateFormater.format(date);
1468            // Most TimeZones are 3 or 4 characters; GMT offsets (e.g. GMT-07:00) are 9, so lets remove the "GMT" part to make it 6
1469            // to fit better
1470            Matcher m = GMT_OFFSET_SHORTEN_PATTERN.matcher(dateString);
1471            if (m.matches() && m.groupCount() == 2) {
1472                dateString = m.group(1) + m.group(2);
1473            }
1474            return dateString;
1475        }
1476    
1477        private void validateCommand(CommandLine commandLine) throws OozieCLIException {
1478            String[] args = commandLine.getArgs();
1479            if (args.length != 1) {
1480                throw new OozieCLIException("One file must be specified");
1481            }
1482            File file = new File(args[0]);
1483            if (file.exists()) {
1484                try {
1485                    List<StreamSource> sources = new ArrayList<StreamSource>();
1486                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1487                            "oozie-workflow-0.1.xsd")));
1488                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1489                            "shell-action-0.1.xsd")));
1490                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1491                            "shell-action-0.2.xsd")));
1492                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1493                            "shell-action-0.3.xsd")));
1494                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1495                            "email-action-0.1.xsd")));
1496                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1497                            "distcp-action-0.1.xsd")));
1498                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1499                            "distcp-action-0.2.xsd")));
1500                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1501                            "oozie-workflow-0.2.xsd")));
1502                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1503                            "oozie-workflow-0.2.5.xsd")));
1504                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1505                            "oozie-workflow-0.3.xsd")));
1506                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1507                            "oozie-workflow-0.4.xsd")));
1508                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1509                            "oozie-coordinator-0.1.xsd")));
1510                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1511                            "oozie-coordinator-0.2.xsd")));
1512                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1513                            "oozie-coordinator-0.3.xsd")));
1514                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1515                            "oozie-coordinator-0.4.xsd")));
1516                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1517                            "oozie-bundle-0.1.xsd")));
1518                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1519                            "oozie-bundle-0.2.xsd")));
1520                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1521                            "oozie-sla-0.1.xsd")));
1522                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1523                            "hive-action-0.2.xsd")));
1524                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1525                            "hive-action-0.3.xsd")));
1526                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1527                            "hive-action-0.4.xsd")));
1528                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1529                            "sqoop-action-0.2.xsd")));
1530                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1531                            "sqoop-action-0.3.xsd")));
1532                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1533                            "sqoop-action-0.4.xsd")));
1534                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1535                            "ssh-action-0.1.xsd")));
1536                    SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
1537                    Schema schema = factory.newSchema(sources.toArray(new StreamSource[sources.size()]));
1538                    Validator validator = schema.newValidator();
1539                    validator.validate(new StreamSource(new FileReader(file)));
1540                    System.out.println("Valid worflow-app");
1541                }
1542                catch (Exception ex) {
1543                    throw new OozieCLIException("Invalid workflow-app, " + ex.toString(), ex);
1544                }
1545            }
1546            else {
1547                throw new OozieCLIException("File does not exists");
1548            }
1549        }
1550    
1551        private void pigCommand(CommandLine commandLine) throws IOException, OozieCLIException {
1552            List<String> pigArgs = commandLine.getArgList();
1553            if (pigArgs.size() > 0) {
1554                // checking is a pigArgs starts with -X (because CLIParser cannot check this)
1555                if (!pigArgs.get(0).equals("-X")) {
1556                    throw new OozieCLIException("Unrecognized option: " + pigArgs.get(0) + " Expecting -X");
1557                }
1558                pigArgs.remove(0);
1559            }
1560    
1561            List<String> options = new ArrayList<String>();
1562            for (Option option : commandLine.getOptions()) {
1563                options.add(option.getOpt());
1564            }
1565    
1566            if (!options.contains(PIGFILE_OPTION)) {
1567                throw new OozieCLIException("Need to specify -file <scriptfile>");
1568            }
1569    
1570            if (!options.contains(CONFIG_OPTION)) {
1571                throw new OozieCLIException("Need to specify -config <configfile>");
1572            }
1573    
1574    
1575            try {
1576                XOozieClient wc = createXOozieClient(commandLine);
1577                Properties conf = getConfiguration(wc, commandLine);
1578                String script = commandLine.getOptionValue(PIGFILE_OPTION);
1579                System.out.println(JOB_ID_PREFIX + wc.submitPig(conf, script, pigArgs.toArray(new String[pigArgs.size()])));
1580            }
1581            catch (OozieClientException ex) {
1582                throw new OozieCLIException(ex.toString(), ex);
1583            }
1584        }
1585    
1586        private void infoCommand(CommandLine commandLine) throws OozieCLIException {
1587            for (Option option : commandLine.getOptions()) {
1588                String opt = option.getOpt();
1589                if (opt.equals(INFO_TIME_ZONES_OPTION)) {
1590                    printAvailableTimeZones();
1591                }
1592            }
1593        }
1594    
1595        private void printAvailableTimeZones() {
1596            System.out.println("The format is \"SHORT_NAME (ID)\"\nGive the ID to the -timezone argument");
1597            System.out.println("GMT offsets can also be used (e.g. GMT-07:00, GMT-0700, GMT+05:30, GMT+0530)");
1598            System.out.println("Available Time Zones:");
1599            for (String tzId : TimeZone.getAvailableIDs()) {
1600                // skip id's that are like "Etc/GMT+01:00" because their display names are like "GMT-01:00", which is confusing
1601                if (!tzId.startsWith("Etc/GMT")) {
1602                    TimeZone tZone = TimeZone.getTimeZone(tzId);
1603                    System.out.println("      " + tZone.getDisplayName(false, TimeZone.SHORT) + " (" + tzId + ")");
1604                }
1605            }
1606        }
1607    
1608    
1609        private void mrCommand(CommandLine commandLine) throws IOException, OozieCLIException {
1610            try {
1611                XOozieClient wc = createXOozieClient(commandLine);
1612                Properties conf = getConfiguration(wc, commandLine);
1613    
1614                String mapper = conf.getProperty(MAPRED_MAPPER);
1615                if (mapper == null) {
1616                    throw new OozieCLIException("mapper is not specified in conf");
1617                }
1618    
1619                String reducer = conf.getProperty(MAPRED_REDUCER);
1620                if (reducer == null) {
1621                    throw new OozieCLIException("reducer is not specified in conf");
1622                }
1623    
1624                String inputDir = conf.getProperty(MAPRED_INPUT);
1625                if (inputDir == null) {
1626                    throw new OozieCLIException("mapred.input.dir is not specified in conf");
1627                }
1628    
1629                String outputDir = conf.getProperty(MAPRED_OUTPUT);
1630                if (outputDir == null) {
1631                    throw new OozieCLIException("mapred.output.dir is not specified in conf");
1632                }
1633    
1634                System.out.println(JOB_ID_PREFIX + wc.submitMapReduce(conf));
1635            }
1636            catch (OozieClientException ex) {
1637                throw new OozieCLIException(ex.toString(), ex);
1638            }
1639        }
1640    }