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    
035    import javax.xml.XMLConstants;
036    import javax.xml.parsers.DocumentBuilder;
037    import javax.xml.parsers.DocumentBuilderFactory;
038    import javax.xml.parsers.ParserConfigurationException;
039    import javax.xml.transform.stream.StreamSource;
040    import javax.xml.validation.Schema;
041    import javax.xml.validation.SchemaFactory;
042    import javax.xml.validation.Validator;
043    
044    import org.apache.commons.cli.CommandLine;
045    import org.apache.commons.cli.Option;
046    import org.apache.commons.cli.OptionBuilder;
047    import org.apache.commons.cli.OptionGroup;
048    import org.apache.commons.cli.Options;
049    import org.apache.commons.cli.ParseException;
050    import org.apache.oozie.BuildInfo;
051    import org.apache.oozie.client.BundleJob;
052    import org.apache.oozie.client.CoordinatorAction;
053    import org.apache.oozie.client.CoordinatorJob;
054    import org.apache.oozie.client.OozieClient;
055    import org.apache.oozie.client.OozieClientException;
056    import org.apache.oozie.client.WorkflowAction;
057    import org.apache.oozie.client.WorkflowJob;
058    import org.apache.oozie.client.XOozieClient;
059    import org.apache.oozie.client.OozieClient.SYSTEM_MODE;
060    import org.apache.oozie.client.rest.RestConstants;
061    import org.w3c.dom.DOMException;
062    import org.w3c.dom.Document;
063    import org.w3c.dom.Element;
064    import org.w3c.dom.Node;
065    import org.w3c.dom.NodeList;
066    import org.w3c.dom.Text;
067    import org.xml.sax.SAXException;
068    
069    /**
070     * Oozie command line utility.
071     */
072    public class OozieCLI {
073        public static final String ENV_OOZIE_URL = "OOZIE_URL";
074        public static final String ENV_OOZIE_DEBUG = "OOZIE_DEBUG";
075        public static final String WS_HEADER_PREFIX = "header:";
076    
077        public static final String HELP_CMD = "help";
078        public static final String VERSION_CMD = "version";
079        public static final String JOB_CMD = "job";
080        public static final String JOBS_CMD = "jobs";
081        public static final String ADMIN_CMD = "admin";
082        public static final String VALIDATE_CMD = "validate";
083        public static final String SLA_CMD = "sla";
084        public static final String PIG_CMD = "pig";
085    
086        public static final String OOZIE_OPTION = "oozie";
087        public static final String CONFIG_OPTION = "config";
088        public static final String SUBMIT_OPTION = "submit";
089        public static final String OFFSET_OPTION = "offset";
090        public static final String START_OPTION = "start";
091        public static final String RUN_OPTION = "run";
092        public static final String DRYRUN_OPTION = "dryrun";
093        public static final String SUSPEND_OPTION = "suspend";
094        public static final String RESUME_OPTION = "resume";
095        public static final String KILL_OPTION = "kill";
096        public static final String CHANGE_OPTION = "change";
097        public static final String CHANGE_VALUE_OPTION = "value";
098        public static final String RERUN_OPTION = "rerun";
099        public static final String INFO_OPTION = "info";
100        public static final String LOG_OPTION = "log";
101        public static final String ACTION_OPTION = "action";
102        public static final String DEFINITION_OPTION = "definition";
103        public static final String CONFIG_CONTENT_OPTION = "configcontent";
104    
105        public static final String LEN_OPTION = "len";
106        public static final String FILTER_OPTION = "filter";
107        public static final String JOBTYPE_OPTION = "jobtype";
108        public static final String SYSTEM_MODE_OPTION = "systemmode";
109        public static final String VERSION_OPTION = "version";
110        public static final String STATUS_OPTION = "status";
111        public static final String LOCAL_TIME_OPTION = "localtime";
112        public static final String QUEUE_DUMP_OPTION = "queuedump";
113        public static final String RERUN_COORD_OPTION = "coordinator";
114        public static final String DATE_OPTION = "date";
115        public static final String RERUN_REFRESH_OPTION = "refresh";
116        public static final String RERUN_NOCLEANUP_OPTION = "nocleanup";
117    
118        public static final String VERBOSE_OPTION = "verbose";
119        public static final String VERBOSE_DELIMITER = "\t";
120    
121        public static final String PIGFILE_OPTION = "file";
122    
123        private static final String[] OOZIE_HELP = {
124                "the env variable '" + ENV_OOZIE_URL + "' is used as default value for the '-" + OOZIE_OPTION + "' option",
125                "custom headers for Oozie web services can be specified using '-D" + WS_HEADER_PREFIX + "NAME=VALUE'" };
126    
127        private static final String RULER;
128        private static final int LINE_WIDTH = 132;
129    
130        private boolean used;
131    
132        static {
133            StringBuilder sb = new StringBuilder();
134            for (int i = 0; i < LINE_WIDTH; i++) {
135                sb.append("-");
136            }
137            RULER = sb.toString();
138        }
139    
140        /**
141         * Entry point for the Oozie CLI when invoked from the command line.
142         * <p/>
143         * Upon completion this method exits the JVM with '0' (success) or '-1' (failure).
144         *
145         * @param args options and arguments for the Oozie CLI.
146         */
147        public static void main(String[] args) {
148            System.exit(new OozieCLI().run(args));
149        }
150    
151        /**
152         * Create an Oozie CLI instance.
153         */
154        public OozieCLI() {
155            used = false;
156        }
157    
158        /**
159         * Return Oozie CLI top help lines.
160         *
161         * @return help lines.
162         */
163        protected String[] getCLIHelp() {
164            return OOZIE_HELP;
165        }
166    
167        protected Options createAdminOptions() {
168            Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL");
169            Option system_mode = new Option(SYSTEM_MODE_OPTION, true,
170                    "Supported in Oozie-2.0 or later versions ONLY. Change oozie system mode [NORMAL|NOWEBSERVICE|SAFEMODE]");
171            Option status = new Option(STATUS_OPTION, false, "show the current system status");
172            Option version = new Option(VERSION_OPTION, false, "show Oozie server build version");
173            Option queuedump = new Option(QUEUE_DUMP_OPTION, false, "show Oozie server queue elements");
174            Options adminOptions = new Options();
175            adminOptions.addOption(oozie);
176            OptionGroup group = new OptionGroup();
177            group.addOption(system_mode);
178            group.addOption(status);
179            group.addOption(version);
180            group.addOption(queuedump);
181            adminOptions.addOptionGroup(group);
182            return adminOptions;
183        }
184    
185        protected Options createJobOptions() {
186            Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL");
187            Option config = new Option(CONFIG_OPTION, true, "job configuration file '.xml' or '.properties'");
188            Option submit = new Option(SUBMIT_OPTION, false, "submit a job");
189            Option run = new Option(RUN_OPTION, false, "run a job");
190            Option rerun = new Option(RERUN_OPTION, true,
191                    "rerun a job  (coordinator requires -action or -date, bundle requires -coordinator or -date)");
192            Option dryrun = new Option(DRYRUN_OPTION, false,
193                    "Supported in Oozie-2.0 or later versions ONLY - dryrun or test run a coordinator job, job is not queued");
194            Option start = new Option(START_OPTION, true, "start a job");
195            Option suspend = new Option(SUSPEND_OPTION, true, "suspend a job");
196            Option resume = new Option(RESUME_OPTION, true, "resume a job");
197            Option kill = new Option(KILL_OPTION, true, "kill a job");
198            Option change = new Option(CHANGE_OPTION, true, "change a coordinator job");
199            Option changeValue = new Option(CHANGE_VALUE_OPTION, true,
200                    "new endtime/concurrency/pausetime value for changing a coordinator job");
201            Option info = new Option(INFO_OPTION, true, "info of a job");
202            Option offset = new Option(OFFSET_OPTION, true, "job info offset of actions (default '1', requires -info)");
203            Option len = new Option(LEN_OPTION, true, "number of actions (default TOTAL ACTIONS, requires -info)");
204            Option localtime = new Option(LOCAL_TIME_OPTION, false, "use local time (default GMT)");
205            Option log = new Option(LOG_OPTION, true, "job log");
206            Option definition = new Option(DEFINITION_OPTION, true, "job definition");
207            Option config_content = new Option(CONFIG_CONTENT_OPTION, true, "job configuration");
208            Option verbose = new Option(VERBOSE_OPTION, false, "verbose mode");
209            Option action = new Option(ACTION_OPTION, true,
210                    "coordinator rerun on action ids (requires -rerun); coordinator log retrieval on action ids (requires -log)");
211            Option date = new Option(DATE_OPTION, true,
212                    "coordinator/bundle rerun on action dates (requires -rerun); coordinator log retrieval on action dates (requires -log)");
213            Option rerun_coord = new Option(RERUN_COORD_OPTION, true, "bundle rerun on coordinator names (requires -rerun)");
214            Option rerun_refresh = new Option(RERUN_REFRESH_OPTION, false,
215                    "re-materialize the coordinator rerun actions (requires -rerun)");
216            Option rerun_nocleanup = new Option(RERUN_NOCLEANUP_OPTION, false,
217                    "do not clean up output-events of the coordiantor rerun actions (requires -rerun)");
218            Option property = OptionBuilder.withArgName("property=value").hasArgs(2).withValueSeparator().withDescription(
219                    "set/override value for given property").create("D");
220    
221            OptionGroup actions = new OptionGroup();
222            actions.addOption(submit);
223            actions.addOption(start);
224            actions.addOption(run);
225            actions.addOption(dryrun);
226            actions.addOption(suspend);
227            actions.addOption(resume);
228            actions.addOption(kill);
229            actions.addOption(change);
230            actions.addOption(info);
231            actions.addOption(rerun);
232            actions.addOption(log);
233            actions.addOption(definition);
234            actions.addOption(config_content);
235            actions.setRequired(true);
236            Options jobOptions = new Options();
237            jobOptions.addOption(oozie);
238            jobOptions.addOption(config);
239            jobOptions.addOption(property);
240            jobOptions.addOption(changeValue);
241            jobOptions.addOption(localtime);
242            jobOptions.addOption(verbose);
243            jobOptions.addOption(offset);
244            jobOptions.addOption(len);
245            jobOptions.addOption(action);
246            jobOptions.addOption(date);
247            jobOptions.addOption(rerun_coord);
248            jobOptions.addOption(rerun_refresh);
249            jobOptions.addOption(rerun_nocleanup);
250            jobOptions.addOptionGroup(actions);
251            return jobOptions;
252        }
253    
254        protected Options createJobsOptions() {
255            Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL");
256            Option start = new Option(OFFSET_OPTION, true, "jobs offset (default '1')");
257            Option jobtype = new Option(JOBTYPE_OPTION, true,
258                    "job type ('Supported in Oozie-2.0 or later versions ONLY - 'coordinator' or 'bundle' or 'wf'(default))");
259            Option len = new Option(LEN_OPTION, true, "number of jobs (default '100')");
260            Option filter = new Option(FILTER_OPTION, true, "user=<U>;name=<N>;group=<G>;status=<S>;...");
261            Option localtime = new Option(LOCAL_TIME_OPTION, false, "use local time (default GMT)");
262            Option verbose = new Option(VERBOSE_OPTION, false, "verbose mode");
263            start.setType(Integer.class);
264            len.setType(Integer.class);
265            Options jobsOptions = new Options();
266            jobsOptions.addOption(oozie);
267            jobsOptions.addOption(localtime);
268            jobsOptions.addOption(start);
269            jobsOptions.addOption(len);
270            jobsOptions.addOption(oozie);
271            jobsOptions.addOption(filter);
272            jobsOptions.addOption(jobtype);
273            jobsOptions.addOption(verbose);
274            return jobsOptions;
275        }
276    
277        protected Options createSlaOptions() {
278            Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL");
279            Option start = new Option(OFFSET_OPTION, true, "start offset (default '0')");
280            Option len = new Option(LEN_OPTION, true, "number of results (default '100')");
281            start.setType(Integer.class);
282            len.setType(Integer.class);
283            Options slaOptions = new Options();
284            slaOptions.addOption(start);
285            slaOptions.addOption(len);
286            slaOptions.addOption(oozie);
287            return slaOptions;
288        }
289    
290        protected Options createPigOptions() {
291            Option oozie = new Option(OOZIE_OPTION, true, "Oozie URL");
292            Option config = new Option(CONFIG_OPTION, true, "job configuration file '.properties'");
293            Option pigFile = new Option(PIGFILE_OPTION, true, "Pig script");
294            Option property = OptionBuilder.withArgName("property=value").hasArgs(2).withValueSeparator().withDescription(
295                    "set/override value for given property").create("D");
296            Options pigOptions = new Options();
297            pigOptions.addOption(oozie);
298            pigOptions.addOption(config);
299            pigOptions.addOption(property);
300            pigOptions.addOption(pigFile);
301            return pigOptions;
302        }
303    
304        /**
305         * Run a CLI programmatically.
306         * <p/>
307         * It does not exit the JVM.
308         * <p/>
309         * A CLI instance can be used only once.
310         *
311         * @param args options and arguments for the Oozie CLI.
312         * @return '0' (success), '-1' (failure).
313         */
314        public synchronized int run(String[] args) {
315            if (used) {
316                throw new IllegalStateException("CLI instance already used");
317            }
318            used = true;
319    
320            CLIParser parser = new CLIParser(OOZIE_OPTION, getCLIHelp());
321            parser.addCommand(HELP_CMD, "", "display usage", new Options(), false);
322            parser.addCommand(VERSION_CMD, "", "show client version", new Options(), false);
323            parser.addCommand(JOB_CMD, "", "job operations", createJobOptions(), false);
324            parser.addCommand(JOBS_CMD, "", "jobs status", createJobsOptions(), false);
325            parser.addCommand(ADMIN_CMD, "", "admin operations", createAdminOptions(), false);
326            parser.addCommand(VALIDATE_CMD, "", "validate a workflow XML file", new Options(), true);
327            parser.addCommand(SLA_CMD, "", "sla operations (Supported in Oozie-2.0 or later)", createSlaOptions(), false);
328            parser.addCommand(PIG_CMD, "-X ", "submit a pig job, everything after '-X' are pass-through parameters to pig",
329                    createPigOptions(), true);
330    
331            try {
332                CLIParser.Command command = parser.parse(args);
333                if (command.getName().equals(HELP_CMD)) {
334                    parser.showHelp();
335                }
336                else if (command.getName().equals(JOB_CMD)) {
337                    jobCommand(command.getCommandLine());
338                }
339                else if (command.getName().equals(JOBS_CMD)) {
340                    jobsCommand(command.getCommandLine());
341                }
342                else if (command.getName().equals(ADMIN_CMD)) {
343                    adminCommand(command.getCommandLine());
344                }
345                else if (command.getName().equals(VERSION_CMD)) {
346                    versionCommand();
347                }
348                else if (command.getName().equals(VALIDATE_CMD)) {
349                    validateCommand(command.getCommandLine());
350                }
351                else if (command.getName().equals(SLA_CMD)) {
352                    slaCommand(command.getCommandLine());
353                }
354                else if (command.getName().equals(PIG_CMD)) {
355                    pigCommand(command.getCommandLine());
356                }
357    
358                return 0;
359            }
360            catch (OozieCLIException ex) {
361                System.err.println("Error: " + ex.getMessage());
362                return -1;
363            }
364            catch (ParseException ex) {
365                System.err.println("Invalid sub-command: " + ex.getMessage());
366                System.err.println();
367                System.err.println(parser.shortHelp());
368                return -1;
369            }
370            catch (Exception ex) {
371                ex.printStackTrace();
372                System.err.println(ex.getMessage());
373                return -1;
374            }
375        }
376    
377        protected String getOozieUrl(CommandLine commandLine) {
378            String url = commandLine.getOptionValue(OOZIE_OPTION);
379            if (url == null) {
380                url = System.getenv(ENV_OOZIE_URL);
381                if (url == null) {
382                    throw new IllegalArgumentException(
383                            "Oozie URL is not available neither in command option or in the environment");
384                }
385            }
386            return url;
387        }
388    
389        // Canibalized from Hadoop <code>Configuration.loadResource()</code>.
390        private Properties parse(InputStream is, Properties conf) throws IOException {
391            try {
392                DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
393                // ignore all comments inside the xml file
394                docBuilderFactory.setIgnoringComments(true);
395                DocumentBuilder builder = docBuilderFactory.newDocumentBuilder();
396                Document doc = builder.parse(is);
397                return parseDocument(doc, conf);
398            }
399            catch (SAXException e) {
400                throw new IOException(e);
401            }
402            catch (ParserConfigurationException e) {
403                throw new IOException(e);
404            }
405        }
406    
407        // Canibalized from Hadoop <code>Configuration.loadResource()</code>.
408        private Properties parseDocument(Document doc, Properties conf) throws IOException {
409            try {
410                Element root = doc.getDocumentElement();
411                if (!"configuration".equals(root.getTagName())) {
412                    throw new RuntimeException("bad conf file: top-level element not <configuration>");
413                }
414                NodeList props = root.getChildNodes();
415                for (int i = 0; i < props.getLength(); i++) {
416                    Node propNode = props.item(i);
417                    if (!(propNode instanceof Element)) {
418                        continue;
419                    }
420                    Element prop = (Element) propNode;
421                    if (!"property".equals(prop.getTagName())) {
422                        throw new RuntimeException("bad conf file: element not <property>");
423                    }
424                    NodeList fields = prop.getChildNodes();
425                    String attr = null;
426                    String value = null;
427                    for (int j = 0; j < fields.getLength(); j++) {
428                        Node fieldNode = fields.item(j);
429                        if (!(fieldNode instanceof Element)) {
430                            continue;
431                        }
432                        Element field = (Element) fieldNode;
433                        if ("name".equals(field.getTagName()) && field.hasChildNodes()) {
434                            attr = ((Text) field.getFirstChild()).getData();
435                        }
436                        if ("value".equals(field.getTagName()) && field.hasChildNodes()) {
437                            value = ((Text) field.getFirstChild()).getData();
438                        }
439                    }
440    
441                    if (attr != null && value != null) {
442                        conf.setProperty(attr, value);
443                    }
444                }
445                return conf;
446            }
447            catch (DOMException e) {
448                throw new IOException(e);
449            }
450        }
451    
452        private Properties getConfiguration(CommandLine commandLine) throws IOException {
453            Properties conf = new Properties();
454            conf.setProperty("user.name", System.getProperty("user.name"));
455            String configFile = commandLine.getOptionValue(CONFIG_OPTION);
456            if (configFile == null) {
457                throw new IOException("configuration file not specified");
458            }
459            else {
460                File file = new File(configFile);
461                if (!file.exists()) {
462                    throw new IOException("configuration file [" + configFile + "] not found");
463                }
464                if (configFile.endsWith(".properties")) {
465                    conf.load(new FileReader(file));
466                }
467                else if (configFile.endsWith(".xml")) {
468                    parse(new FileInputStream(configFile), conf);
469                }
470                else {
471                    throw new IllegalArgumentException("configuration must be a '.properties' or a '.xml' file");
472                }
473            }
474            if (commandLine.hasOption("D")) {
475                Properties commandLineProperties = commandLine.getOptionProperties("D");
476                conf.putAll(commandLineProperties);
477            }
478            return conf;
479        }
480    
481        /**
482         * @param commandLine command line string.
483         * @return change value specified by -value.
484         * @throws OozieCLIException
485         */
486        private String getChangeValue(CommandLine commandLine) throws OozieCLIException {
487            String changeValue = commandLine.getOptionValue(CHANGE_VALUE_OPTION);
488    
489            if (changeValue == null) {
490                throw new OozieCLIException("-value option needs to be specified for -change option");
491            }
492    
493            return changeValue;
494        }
495    
496        private void addHeader(OozieClient wc) {
497            for (Map.Entry entry : System.getProperties().entrySet()) {
498                String key = (String) entry.getKey();
499                if (key.startsWith(WS_HEADER_PREFIX)) {
500                    String header = key.substring(WS_HEADER_PREFIX.length());
501                    wc.setHeader(header, (String) entry.getValue());
502                }
503            }
504        }
505    
506        /**
507         * Create a OozieClient.
508         * <p/>
509         * It injects any '-Dheader:' as header to the the {@link org.apache.oozie.client.OozieClient}.
510         *
511         * @param commandLine the parsed command line options.
512         * @return a pre configured eXtended workflow client.
513         * @throws OozieCLIException thrown if the OozieClient could not be configured.
514         */
515        protected OozieClient createOozieClient(CommandLine commandLine) throws OozieCLIException {
516            OozieClient wc = new OozieClient(getOozieUrl(commandLine));
517            addHeader(wc);
518            setDebugMode(wc);
519            return wc;
520        }
521    
522        /**
523         * Create a XOozieClient.
524         * <p/>
525         * It injects any '-Dheader:' as header to the the {@link org.apache.oozie.client.OozieClient}.
526         *
527         * @param commandLine the parsed command line options.
528         * @return a pre configured eXtended workflow client.
529         * @throws OozieCLIException thrown if the XOozieClient could not be configured.
530         */
531        protected XOozieClient createXOozieClient(CommandLine commandLine) throws OozieCLIException {
532            XOozieClient wc = new XOozieClient(getOozieUrl(commandLine));
533            addHeader(wc);
534            setDebugMode(wc);
535            return wc;
536        }
537    
538        protected void setDebugMode(OozieClient wc) {
539            String debug = System.getenv(ENV_OOZIE_DEBUG);
540            if (debug != null && !debug.isEmpty()) {
541                int debugVal = 0;
542                try {
543                    debugVal = Integer.parseInt(debug.trim());
544                }
545                catch (Exception ex) {
546                    System.out.println("Unable to parse the debug settings. May be not an integer [" + debug + "]");
547                    ex.printStackTrace();
548                }
549                wc.setDebugMode(debugVal);
550            }
551        }
552    
553        private static String JOB_ID_PREFIX = "job: ";
554    
555        private void jobCommand(CommandLine commandLine) throws IOException, OozieCLIException {
556            XOozieClient wc = createXOozieClient(commandLine);
557    
558            List<String> options = new ArrayList<String>();
559            for (Option option : commandLine.getOptions()) {
560                options.add(option.getOpt());
561            }
562    
563            try {
564                if (options.contains(SUBMIT_OPTION)) {
565                    System.out.println(JOB_ID_PREFIX + wc.submit(getConfiguration(commandLine)));
566                }
567                else if (options.contains(START_OPTION)) {
568                    wc.start(commandLine.getOptionValue(START_OPTION));
569                }
570                else if (options.contains(DRYRUN_OPTION)) {
571                    String[] dryrunStr = wc.dryrun(getConfiguration(commandLine)).split("action for new instance");
572                    int arraysize = dryrunStr.length;
573                    System.out.println("***coordJob after parsing: ***");
574                    System.out.println(dryrunStr[0]);
575                    int aLen = dryrunStr.length - 1;
576                    if (aLen < 0) {
577                        aLen = 0;
578                    }
579                    System.out.println("***total coord actions is " + aLen + " ***");
580                    for (int i = 1; i <= arraysize - 1; i++) {
581                        System.out.println(RULER);
582                        System.out.println("coordAction instance: " + i + ":");
583                        System.out.println(dryrunStr[i]);
584                    }
585                }
586                else if (options.contains(SUSPEND_OPTION)) {
587                    wc.suspend(commandLine.getOptionValue(SUSPEND_OPTION));
588                }
589                else if (options.contains(RESUME_OPTION)) {
590                    wc.resume(commandLine.getOptionValue(RESUME_OPTION));
591                }
592                else if (options.contains(KILL_OPTION)) {
593                    wc.kill(commandLine.getOptionValue(KILL_OPTION));
594                }
595                else if (options.contains(CHANGE_OPTION)) {
596                    wc.change(commandLine.getOptionValue(CHANGE_OPTION), getChangeValue(commandLine));
597                }
598                else if (options.contains(RUN_OPTION)) {
599                    System.out.println(JOB_ID_PREFIX + wc.run(getConfiguration(commandLine)));
600                }
601                else if (options.contains(RERUN_OPTION)) {
602                    if (commandLine.getOptionValue(RERUN_OPTION).contains("-W")) {
603                        wc.reRun(commandLine.getOptionValue(RERUN_OPTION), getConfiguration(commandLine));
604                    }
605                    else if (commandLine.getOptionValue(RERUN_OPTION).contains("-B")) {
606                        String bundleJobId = commandLine.getOptionValue(RERUN_OPTION);
607                        String coordScope = null;
608                        String dateScope = null;
609                        boolean refresh = false;
610                        boolean noCleanup = false;
611                        if (options.contains(ACTION_OPTION)) {
612                            throw new OozieCLIException("Invalid options provided for bundle rerun. " + ACTION_OPTION
613                                    + " is not valid for bundle rerun");
614                        }
615                        if (options.contains(DATE_OPTION)) {
616                            dateScope = commandLine.getOptionValue(DATE_OPTION);
617                        }
618    
619                        if (options.contains(RERUN_COORD_OPTION)) {
620                            coordScope = commandLine.getOptionValue(RERUN_COORD_OPTION);
621                        }
622    
623                        if (options.contains(RERUN_REFRESH_OPTION)) {
624                            refresh = true;
625                        }
626                        if (options.contains(RERUN_NOCLEANUP_OPTION)) {
627                            noCleanup = true;
628                        }
629                        wc.reRunBundle(bundleJobId, coordScope, dateScope, refresh, noCleanup);
630                        if (coordScope != null && !coordScope.isEmpty()) {
631                            System.out.println("Coordinators [" + coordScope + "] of bundle " + bundleJobId
632                                    + " are scheduled to rerun on date ranges [" + dateScope + "].");
633                        }
634                        else {
635                            System.out.println("All coordinators of bundle " + bundleJobId
636                                    + " are scheduled to rerun on the date ranges [" + dateScope + "].");
637                        }
638                    }
639                    else {
640                        String coordJobId = commandLine.getOptionValue(RERUN_OPTION);
641                        String scope = null;
642                        String rerunType = null;
643                        boolean refresh = false;
644                        boolean noCleanup = false;
645                        if (options.contains(DATE_OPTION) && options.contains(ACTION_OPTION)) {
646                            throw new OozieCLIException("Invalid options provided for rerun: either" + DATE_OPTION + " or "
647                                    + ACTION_OPTION + " expected. Don't use both at the same time.");
648                        }
649                        if (options.contains(DATE_OPTION)) {
650                            rerunType = RestConstants.JOB_COORD_RERUN_DATE;
651                            scope = commandLine.getOptionValue(DATE_OPTION);
652                        }
653                        else if (options.contains(ACTION_OPTION)) {
654                            rerunType = RestConstants.JOB_COORD_RERUN_ACTION;
655                            scope = commandLine.getOptionValue(ACTION_OPTION);
656                        }
657                        else {
658                            throw new OozieCLIException("Invalid options provided for rerun: " + DATE_OPTION + " or "
659                                    + ACTION_OPTION + " expected.");
660                        }
661                        if (options.contains(RERUN_REFRESH_OPTION)) {
662                            refresh = true;
663                        }
664                        if (options.contains(RERUN_NOCLEANUP_OPTION)) {
665                            noCleanup = true;
666                        }
667                        printRerunCoordActions(wc.reRunCoord(coordJobId, rerunType, scope, refresh, noCleanup));
668                    }
669                }
670                else if (options.contains(INFO_OPTION)) {
671                    if (commandLine.getOptionValue(INFO_OPTION).endsWith("-B")) {
672                        printBundleJob(wc.getBundleJobInfo(commandLine.getOptionValue(INFO_OPTION)), options
673                                .contains(LOCAL_TIME_OPTION), options.contains(VERBOSE_OPTION));
674                    }
675                    else if (commandLine.getOptionValue(INFO_OPTION).endsWith("-C")) {
676                        String s = commandLine.getOptionValue(OFFSET_OPTION);
677                        int start = Integer.parseInt((s != null) ? s : "0");
678                        s = commandLine.getOptionValue(LEN_OPTION);
679                        int len = Integer.parseInt((s != null) ? s : "0");
680                        printCoordJob(wc.getCoordJobInfo(commandLine.getOptionValue(INFO_OPTION), start, len), options
681                                .contains(LOCAL_TIME_OPTION), options.contains(VERBOSE_OPTION));
682                    }
683                    else if (commandLine.getOptionValue(INFO_OPTION).contains("-C@")) {
684                        printCoordAction(wc.getCoordActionInfo(commandLine.getOptionValue(INFO_OPTION)), options
685                                .contains(LOCAL_TIME_OPTION));
686                    }
687                    else if (commandLine.getOptionValue(INFO_OPTION).contains("-W@")) {
688                        printWorkflowAction(wc.getWorkflowActionInfo(commandLine.getOptionValue(INFO_OPTION)), options
689                                .contains(LOCAL_TIME_OPTION));
690                    }
691                    else {
692                        String s = commandLine.getOptionValue(OFFSET_OPTION);
693                        int start = Integer.parseInt((s != null) ? s : "0");
694                        s = commandLine.getOptionValue(LEN_OPTION);
695                        String jobtype = commandLine.getOptionValue(JOBTYPE_OPTION);
696                        jobtype = (jobtype != null) ? jobtype : "wf";
697                        int len = Integer.parseInt((s != null) ? s : "0");
698                        printJob(wc.getJobInfo(commandLine.getOptionValue(INFO_OPTION), start, len), options
699                                .contains(LOCAL_TIME_OPTION), options.contains(VERBOSE_OPTION));
700                    }
701                }
702                else if (options.contains(LOG_OPTION)) {
703                    PrintStream ps = System.out;
704                    if (commandLine.getOptionValue(LOG_OPTION).contains("-C")) {
705                        String logRetrievalScope = null;
706                        String logRetrievalType = null;
707                        if (options.contains(ACTION_OPTION)) {
708                            logRetrievalType = RestConstants.JOB_LOG_ACTION;
709                            logRetrievalScope = commandLine.getOptionValue(ACTION_OPTION);
710                        }
711                        if (options.contains(DATE_OPTION)) {
712                            logRetrievalType = RestConstants.JOB_LOG_DATE;
713                            logRetrievalScope = commandLine.getOptionValue(DATE_OPTION);
714                        }
715                        try {
716                            wc.getJobLog(commandLine.getOptionValue(LOG_OPTION), logRetrievalType, logRetrievalScope, ps);
717                        }
718                        finally {
719                            ps.close();
720                        }
721                    }
722                    else {
723                        if (!options.contains(ACTION_OPTION) && !options.contains(DATE_OPTION)) {
724                            wc.getJobLog(commandLine.getOptionValue(LOG_OPTION), null, null, ps);
725                        }
726                        else {
727                            throw new OozieCLIException("Invalid options provided for log retrieval. " + ACTION_OPTION
728                                    + " and " + DATE_OPTION + " are valid only for coordinator job log retrieval");
729                        }
730                    }
731                }
732                else if (options.contains(DEFINITION_OPTION)) {
733                    System.out.println(wc.getJobDefinition(commandLine.getOptionValue(DEFINITION_OPTION)));
734                }
735                else if (options.contains(CONFIG_CONTENT_OPTION)) {
736                    if (commandLine.getOptionValue(CONFIG_CONTENT_OPTION).endsWith("-C")) {
737                        System.out.println(wc.getCoordJobInfo(commandLine.getOptionValue(CONFIG_CONTENT_OPTION)).getConf());
738                    }
739                    else if (commandLine.getOptionValue(CONFIG_CONTENT_OPTION).endsWith("-W")) {
740                        System.out.println(wc.getJobInfo(commandLine.getOptionValue(CONFIG_CONTENT_OPTION)).getConf());
741                    }
742                    else if (commandLine.getOptionValue(CONFIG_CONTENT_OPTION).endsWith("-B")) {
743                        System.out
744                                .println(wc.getBundleJobInfo(commandLine.getOptionValue(CONFIG_CONTENT_OPTION)).getConf());
745                    }
746                    else {
747                        System.out.println("ERROR:  job id [" + commandLine.getOptionValue(CONFIG_CONTENT_OPTION)
748                                + "] doesn't end with either C or W or B");
749                    }
750                }
751            }
752            catch (OozieClientException ex) {
753                throw new OozieCLIException(ex.toString(), ex);
754            }
755        }
756    
757        private void printCoordJob(CoordinatorJob coordJob, boolean localtime, boolean verbose) {
758            System.out.println("Job ID : " + coordJob.getId());
759    
760            System.out.println(RULER);
761    
762            List<CoordinatorAction> actions = coordJob.getActions();
763            System.out.println("Job Name : " + maskIfNull(coordJob.getAppName()));
764            System.out.println("App Path : " + maskIfNull(coordJob.getAppPath()));
765            System.out.println("Status   : " + coordJob.getStatus());
766            System.out.println(RULER);
767    
768            if (verbose) {
769                System.out.println("ID" + VERBOSE_DELIMITER + "Action Number" + VERBOSE_DELIMITER + "Console URL"
770                        + VERBOSE_DELIMITER + "Error Code" + VERBOSE_DELIMITER + "Error Message" + VERBOSE_DELIMITER
771                        + "External ID" + VERBOSE_DELIMITER + "External Status" + VERBOSE_DELIMITER + "Job ID"
772                        + VERBOSE_DELIMITER + "Tracker URI" + VERBOSE_DELIMITER + "Created" + VERBOSE_DELIMITER
773                        + "Nominal Time" + VERBOSE_DELIMITER + "Status" + VERBOSE_DELIMITER + "Last Modified"
774                        + VERBOSE_DELIMITER + "Missing Dependencies");
775                System.out.println(RULER);
776    
777                for (CoordinatorAction action : actions) {
778                    System.out.println(maskIfNull(action.getId()) + VERBOSE_DELIMITER + action.getActionNumber()
779                            + VERBOSE_DELIMITER + maskIfNull(action.getConsoleUrl()) + VERBOSE_DELIMITER
780                            + maskIfNull(action.getErrorCode()) + VERBOSE_DELIMITER + maskIfNull(action.getErrorMessage())
781                            + VERBOSE_DELIMITER + maskIfNull(action.getExternalId()) + VERBOSE_DELIMITER
782                            + maskIfNull(action.getExternalStatus()) + VERBOSE_DELIMITER + maskIfNull(action.getJobId())
783                            + VERBOSE_DELIMITER + maskIfNull(action.getTrackerUri()) + VERBOSE_DELIMITER
784                            + maskDate(action.getCreatedTime(), localtime) + VERBOSE_DELIMITER
785                            + maskDate(action.getNominalTime(), localtime) + action.getStatus() + VERBOSE_DELIMITER
786                            + maskDate(action.getLastModifiedTime(), localtime) + VERBOSE_DELIMITER
787                            + maskIfNull(action.getMissingDependencies()));
788    
789                    System.out.println(RULER);
790                }
791            }
792            else {
793                System.out.println(String.format(COORD_ACTION_FORMATTER, "ID", "Status", "Ext ID", "Err Code", "Created",
794                        "Nominal Time", "Last Mod"));
795    
796                for (CoordinatorAction action : actions) {
797                    System.out.println(String.format(COORD_ACTION_FORMATTER, maskIfNull(action.getId()),
798                            action.getStatus(), maskIfNull(action.getExternalId()), maskIfNull(action.getErrorCode()),
799                            maskDate(action.getCreatedTime(), localtime), maskDate(action.getNominalTime(), localtime),
800                            maskDate(action.getLastModifiedTime(), localtime)));
801    
802                    System.out.println(RULER);
803                }
804            }
805        }
806    
807        private void printBundleJob(BundleJob bundleJob, boolean localtime, boolean verbose) {
808            System.out.println("Job ID : " + bundleJob.getId());
809    
810            System.out.println(RULER);
811    
812            List<CoordinatorJob> coordinators = bundleJob.getCoordinators();
813            System.out.println("Job Name : " + maskIfNull(bundleJob.getAppName()));
814            System.out.println("App Path : " + maskIfNull(bundleJob.getAppPath()));
815            System.out.println("Status   : " + bundleJob.getStatus());
816            System.out.println("Kickoff time   : " + bundleJob.getKickoffTime());
817            System.out.println(RULER);
818    
819            System.out.println(String.format(BUNDLE_COORD_JOBS_FORMATTER, "Job ID", "Status", "Freq", "Unit", "Started",
820                    "Next Materialized"));
821            System.out.println(RULER);
822    
823            for (CoordinatorJob job : coordinators) {
824                System.out.println(String.format(BUNDLE_COORD_JOBS_FORMATTER, maskIfNull(job.getId()), job.getStatus(), job
825                        .getFrequency(), job.getTimeUnit(), maskDate(job.getStartTime(), localtime), maskDate(job
826                        .getNextMaterializedTime(), localtime)));
827    
828                System.out.println(RULER);
829            }
830        }
831    
832        private void printCoordAction(CoordinatorAction coordAction, boolean contains) {
833            System.out.println("ID : " + maskIfNull(coordAction.getId()));
834    
835            System.out.println(RULER);
836    
837            System.out.println("Action Number        : " + coordAction.getActionNumber());
838            System.out.println("Console URL          : " + maskIfNull(coordAction.getConsoleUrl()));
839            System.out.println("Error Code           : " + maskIfNull(coordAction.getErrorCode()));
840            System.out.println("Error Message        : " + maskIfNull(coordAction.getErrorMessage()));
841            System.out.println("External ID          : " + maskIfNull(coordAction.getExternalId()));
842            System.out.println("External Status      : " + maskIfNull(coordAction.getExternalStatus()));
843            System.out.println("Job ID               : " + maskIfNull(coordAction.getJobId()));
844            System.out.println("Tracker URI          : " + maskIfNull(coordAction.getTrackerUri()));
845            System.out.println("Created              : " + maskDate(coordAction.getCreatedTime(), contains));
846            System.out.println("Nominal Time         : " + maskDate(coordAction.getNominalTime(), contains));
847            System.out.println("Status               : " + coordAction.getStatus());
848            System.out.println("Last Modified        : " + maskDate(coordAction.getLastModifiedTime(), contains));
849            System.out.println("Missing Dependencies : " + maskIfNull(coordAction.getMissingDependencies()));
850    
851            System.out.println(RULER);
852        }
853    
854        private void printRerunCoordActions(List<CoordinatorAction> actions) {
855            if (actions != null && actions.size() > 0) {
856                System.out.println("Action ID" + VERBOSE_DELIMITER + "Nominal Time");
857                System.out.println(RULER);
858                for (CoordinatorAction action : actions) {
859                    System.out.println(maskIfNull(action.getId()) + VERBOSE_DELIMITER
860                            + maskDate(action.getNominalTime(), false));
861                }
862            }
863            else {
864                System.out.println("No Actions match your rerun criteria!");
865            }
866        }
867    
868        private void printWorkflowAction(WorkflowAction action, boolean contains) {
869            System.out.println("ID : " + maskIfNull(action.getId()));
870    
871            System.out.println(RULER);
872    
873            System.out.println("Console URL     : " + maskIfNull(action.getConsoleUrl()));
874            System.out.println("Error Code      : " + maskIfNull(action.getErrorCode()));
875            System.out.println("Error Message   : " + maskIfNull(action.getErrorMessage()));
876            System.out.println("External ID     : " + maskIfNull(action.getExternalId()));
877            System.out.println("External Status : " + maskIfNull(action.getExternalStatus()));
878            System.out.println("Name            : " + maskIfNull(action.getName()));
879            System.out.println("Retries         : " + action.getRetries());
880            System.out.println("Tracker URI     : " + maskIfNull(action.getTrackerUri()));
881            System.out.println("Type            : " + maskIfNull(action.getType()));
882            System.out.println("Started         : " + maskDate(action.getStartTime(), contains));
883            System.out.println("Status          : " + action.getStatus());
884            System.out.println("Ended           : " + maskDate(action.getEndTime(), contains));
885    
886            System.out.println(RULER);
887        }
888    
889        private static final String WORKFLOW_JOBS_FORMATTER = "%-41s%-13s%-10s%-10s%-10s%-24s%-24s";
890        private static final String COORD_JOBS_FORMATTER = "%-41s%-15s%-10s%-5s%-13s%-24s%-24s";
891        private static final String BUNDLE_JOBS_FORMATTER = "%-41s%-15s%-10s%-20s%-20s%-13s%-13s";
892        private static final String BUNDLE_COORD_JOBS_FORMATTER = "%-41s%-10s%-5s%-13s%-24s%-24s";
893    
894        private static final String WORKFLOW_ACTION_FORMATTER = "%-78s%-10s%-23s%-11s%-10s";
895        private static final String COORD_ACTION_FORMATTER = "%-43s%-10s%-37s%-10s%-17s%-17s";
896    
897        private void printJob(WorkflowJob job, boolean localtime, boolean verbose) throws IOException {
898            System.out.println("Job ID : " + maskIfNull(job.getId()));
899    
900            System.out.println(RULER);
901    
902            System.out.println("Workflow Name : " + maskIfNull(job.getAppName()));
903            System.out.println("App Path      : " + maskIfNull(job.getAppPath()));
904            System.out.println("Status        : " + job.getStatus());
905            System.out.println("Run           : " + job.getRun());
906            System.out.println("User          : " + maskIfNull(job.getUser()));
907            System.out.println("Group         : " + maskIfNull(job.getGroup()));
908            System.out.println("Created       : " + maskDate(job.getCreatedTime(), localtime));
909            System.out.println("Started       : " + maskDate(job.getStartTime(), localtime));
910            System.out.println("Last Modified : " + maskDate(job.getLastModifiedTime(), localtime));
911            System.out.println("Ended         : " + maskDate(job.getEndTime(), localtime));
912            System.out.println("CoordAction ID: " + maskIfNull(job.getParentId()));
913    
914            List<WorkflowAction> actions = job.getActions();
915    
916            if (actions != null && actions.size() > 0) {
917                System.out.println();
918                System.out.println("Actions");
919                System.out.println(RULER);
920    
921                if (verbose) {
922                    System.out.println("ID" + VERBOSE_DELIMITER + "Console URL" + VERBOSE_DELIMITER + "Error Code"
923                            + VERBOSE_DELIMITER + "Error Message" + VERBOSE_DELIMITER + "External ID" + VERBOSE_DELIMITER
924                            + "External Status" + VERBOSE_DELIMITER + "Name" + VERBOSE_DELIMITER + "Retries"
925                            + VERBOSE_DELIMITER + "Tracker URI" + VERBOSE_DELIMITER + "Type" + VERBOSE_DELIMITER
926                            + "Started" + VERBOSE_DELIMITER + "Status" + VERBOSE_DELIMITER + "Ended");
927                    System.out.println(RULER);
928    
929                    for (WorkflowAction action : job.getActions()) {
930                        System.out.println(maskIfNull(action.getId()) + VERBOSE_DELIMITER
931                                + maskIfNull(action.getConsoleUrl()) + VERBOSE_DELIMITER
932                                + maskIfNull(action.getErrorCode()) + VERBOSE_DELIMITER
933                                + maskIfNull(action.getErrorMessage()) + VERBOSE_DELIMITER
934                                + maskIfNull(action.getExternalId()) + VERBOSE_DELIMITER
935                                + maskIfNull(action.getExternalStatus()) + VERBOSE_DELIMITER + maskIfNull(action.getName())
936                                + VERBOSE_DELIMITER + action.getRetries() + VERBOSE_DELIMITER
937                                + maskIfNull(action.getTrackerUri()) + VERBOSE_DELIMITER + maskIfNull(action.getType())
938                                + VERBOSE_DELIMITER + maskDate(action.getStartTime(), localtime) + VERBOSE_DELIMITER
939                                + action.getStatus() + VERBOSE_DELIMITER + maskDate(action.getEndTime(), localtime));
940    
941                        System.out.println(RULER);
942                    }
943                }
944                else {
945                    System.out.println(String.format(WORKFLOW_ACTION_FORMATTER, "ID", "Status", "Ext ID", "Ext Status",
946                            "Err Code"));
947    
948                    System.out.println(RULER);
949    
950                    for (WorkflowAction action : job.getActions()) {
951                        System.out.println(String.format(WORKFLOW_ACTION_FORMATTER, maskIfNull(action.getId()), action
952                                .getStatus(), maskIfNull(action.getExternalId()), maskIfNull(action.getExternalStatus()),
953                                maskIfNull(action.getErrorCode())));
954    
955                        System.out.println(RULER);
956                    }
957                }
958            }
959            else {
960                System.out.println(RULER);
961            }
962    
963            System.out.println();
964        }
965    
966        private void jobsCommand(CommandLine commandLine) throws IOException, OozieCLIException {
967            XOozieClient wc = createXOozieClient(commandLine);
968    
969            String filter = commandLine.getOptionValue(FILTER_OPTION);
970            String s = commandLine.getOptionValue(OFFSET_OPTION);
971            int start = Integer.parseInt((s != null) ? s : "0");
972            s = commandLine.getOptionValue(LEN_OPTION);
973            String jobtype = commandLine.getOptionValue(JOBTYPE_OPTION);
974            jobtype = (jobtype != null) ? jobtype : "wf";
975            int len = Integer.parseInt((s != null) ? s : "0");
976            try {
977                if (jobtype.toLowerCase().contains("wf")) {
978                    printJobs(wc.getJobsInfo(filter, start, len), commandLine.hasOption(LOCAL_TIME_OPTION), commandLine
979                            .hasOption(VERBOSE_OPTION));
980                }
981                else if (jobtype.toLowerCase().startsWith("coord")) {
982                    printCoordJobs(wc.getCoordJobsInfo(filter, start, len), commandLine.hasOption(LOCAL_TIME_OPTION),
983                            commandLine.hasOption(VERBOSE_OPTION));
984                }
985                else if (jobtype.toLowerCase().startsWith("bundle")) {
986                    printBundleJobs(wc.getBundleJobsInfo(filter, start, len), commandLine.hasOption(LOCAL_TIME_OPTION),
987                            commandLine.hasOption(VERBOSE_OPTION));
988                }
989    
990            }
991            catch (OozieClientException ex) {
992                throw new OozieCLIException(ex.toString(), ex);
993            }
994        }
995    
996        private void printCoordJobs(List<CoordinatorJob> jobs, boolean localtime, boolean verbose) throws IOException {
997            if (jobs != null && jobs.size() > 0) {
998                if (verbose) {
999                    System.out.println("Job ID" + VERBOSE_DELIMITER + "App Name" + VERBOSE_DELIMITER + "App Path"
1000                            + VERBOSE_DELIMITER + "Console URL" + VERBOSE_DELIMITER + "User" + VERBOSE_DELIMITER + "Group"
1001                            + VERBOSE_DELIMITER + "Concurrency" + VERBOSE_DELIMITER + "Frequency" + VERBOSE_DELIMITER
1002                            + "Time Unit" + VERBOSE_DELIMITER + "Time Zone" + VERBOSE_DELIMITER + "Time Out"
1003                            + VERBOSE_DELIMITER + "Started" + VERBOSE_DELIMITER + "Next Materialize" + VERBOSE_DELIMITER
1004                            + "Status" + VERBOSE_DELIMITER + "Last Action" + VERBOSE_DELIMITER + "Ended");
1005                    System.out.println(RULER);
1006    
1007                    for (CoordinatorJob job : jobs) {
1008                        System.out.println(maskIfNull(job.getId()) + VERBOSE_DELIMITER + maskIfNull(job.getAppName())
1009                                + VERBOSE_DELIMITER + maskIfNull(job.getAppPath()) + VERBOSE_DELIMITER
1010                                + maskIfNull(job.getConsoleUrl()) + VERBOSE_DELIMITER + maskIfNull(job.getUser())
1011                                + VERBOSE_DELIMITER + maskIfNull(job.getGroup()) + VERBOSE_DELIMITER + job.getConcurrency()
1012                                + VERBOSE_DELIMITER + job.getFrequency() + VERBOSE_DELIMITER + job.getTimeUnit()
1013                                + VERBOSE_DELIMITER + maskIfNull(job.getTimeZone()) + VERBOSE_DELIMITER + job.getTimeout()
1014                                + VERBOSE_DELIMITER + maskDate(job.getStartTime(), localtime) + VERBOSE_DELIMITER
1015                                + maskDate(job.getNextMaterializedTime(), localtime) + VERBOSE_DELIMITER + job.getStatus()
1016                                + VERBOSE_DELIMITER + maskDate(job.getLastActionTime(), localtime) + VERBOSE_DELIMITER
1017                                + maskDate(job.getEndTime(), localtime));
1018    
1019                        System.out.println(RULER);
1020                    }
1021                }
1022                else {
1023                    System.out.println(String.format(COORD_JOBS_FORMATTER, "Job ID", "App Name", "Status", "Freq", "Unit",
1024                            "Started", "Next Materialized"));
1025                    System.out.println(RULER);
1026    
1027                    for (CoordinatorJob job : jobs) {
1028                        System.out.println(String.format(COORD_JOBS_FORMATTER, maskIfNull(job.getId()), maskIfNull(job
1029                                .getAppName()), job.getStatus(), job.getFrequency(), job.getTimeUnit(), maskDate(job
1030                                .getStartTime(), localtime), maskDate(job.getNextMaterializedTime(), localtime)));
1031    
1032                        System.out.println(RULER);
1033                    }
1034                }
1035            }
1036            else {
1037                System.out.println("No Jobs match your criteria!");
1038            }
1039        }
1040    
1041        private void printBundleJobs(List<BundleJob> jobs, boolean localtime, boolean verbose) throws IOException {
1042            if (jobs != null && jobs.size() > 0) {
1043                if (verbose) {
1044                    System.out.println("Job ID" + VERBOSE_DELIMITER + "Bundle Name" + VERBOSE_DELIMITER + "Bundle Path"
1045                            + VERBOSE_DELIMITER + "User" + VERBOSE_DELIMITER + "Group" + VERBOSE_DELIMITER + "Status"
1046                            + VERBOSE_DELIMITER + "Kickoff" + VERBOSE_DELIMITER + "Pause" + VERBOSE_DELIMITER + "Created"
1047                            + VERBOSE_DELIMITER + "Console URL");
1048                    System.out.println(RULER);
1049    
1050                    for (BundleJob job : jobs) {
1051                        System.out.println(maskIfNull(job.getId()) + VERBOSE_DELIMITER + maskIfNull(job.getAppName())
1052                                + VERBOSE_DELIMITER + maskIfNull(job.getAppPath()) + VERBOSE_DELIMITER
1053                                + maskIfNull(job.getUser()) + VERBOSE_DELIMITER + maskIfNull(job.getGroup())
1054                                + VERBOSE_DELIMITER + job.getStatus() + VERBOSE_DELIMITER
1055                                + maskDate(job.getKickoffTime(), localtime) + VERBOSE_DELIMITER
1056                                + maskDate(job.getPauseTime(), localtime) + VERBOSE_DELIMITER
1057                                + maskDate(job.getCreatedTime(), localtime) + VERBOSE_DELIMITER
1058                                + maskIfNull(job.getConsoleUrl()));
1059    
1060                        System.out.println(RULER);
1061                    }
1062                }
1063                else {
1064                    System.out.println(String.format(BUNDLE_JOBS_FORMATTER, "Job ID", "Bundle Name", "Status", "Kickoff",
1065                            "Created", "User", "Group"));
1066                    System.out.println(RULER);
1067    
1068                    for (BundleJob job : jobs) {
1069                        System.out.println(String.format(BUNDLE_JOBS_FORMATTER, maskIfNull(job.getId()), maskIfNull(job
1070                                .getAppName()), job.getStatus(), maskDate(job.getKickoffTime(), localtime), maskDate(job
1071                                .getCreatedTime(), localtime), maskIfNull(job.getUser()), maskIfNull(job.getGroup())));
1072                        System.out.println(RULER);
1073                    }
1074                }
1075            }
1076            else {
1077                System.out.println("No Jobs match your criteria!");
1078            }
1079        }
1080    
1081        private void slaCommand(CommandLine commandLine) throws IOException, OozieCLIException {
1082            XOozieClient wc = createXOozieClient(commandLine);
1083            String s = commandLine.getOptionValue(OFFSET_OPTION);
1084            int start = Integer.parseInt((s != null) ? s : "0");
1085            s = commandLine.getOptionValue(LEN_OPTION);
1086            int len = Integer.parseInt((s != null) ? s : "100");
1087            try {
1088                wc.getSlaInfo(start, len);
1089            }
1090            catch (OozieClientException ex) {
1091                throw new OozieCLIException(ex.toString(), ex);
1092            }
1093        }
1094    
1095        private void adminCommand(CommandLine commandLine) throws OozieCLIException {
1096            XOozieClient wc = createXOozieClient(commandLine);
1097    
1098            List<String> options = new ArrayList<String>();
1099            for (Option option : commandLine.getOptions()) {
1100                options.add(option.getOpt());
1101            }
1102    
1103            try {
1104                SYSTEM_MODE status = SYSTEM_MODE.NORMAL;
1105                if (options.contains(VERSION_OPTION)) {
1106                    System.out.println("Oozie server build version: " + wc.getServerBuildVersion());
1107                }
1108                else if (options.contains(SYSTEM_MODE_OPTION)) {
1109                    String systemModeOption = commandLine.getOptionValue(SYSTEM_MODE_OPTION).toUpperCase();
1110                    try {
1111                        status = SYSTEM_MODE.valueOf(systemModeOption);
1112                    }
1113                    catch (Exception e) {
1114                        throw new OozieCLIException("Invalid input provided for option: " + SYSTEM_MODE_OPTION
1115                                + " value given :" + systemModeOption
1116                                + " Expected values are: NORMAL/NOWEBSERVICE/SAFEMODE ");
1117                    }
1118                    wc.setSystemMode(status);
1119                    System.out.println("System mode: " + status);
1120                }
1121                else if (options.contains(STATUS_OPTION)) {
1122                    status = wc.getSystemMode();
1123                    System.out.println("System mode: " + status);
1124                }
1125                else if (options.contains(QUEUE_DUMP_OPTION)) {
1126    
1127                    List<String> list = wc.getQueueDump();
1128                    if (list != null && list.size() != 0) {
1129                        for (String str : list) {
1130                            System.out.println(str);
1131                        }
1132                    }
1133                    else {
1134                        System.out.println("QueueDump is null!");
1135                    }
1136                }
1137            }
1138            catch (OozieClientException ex) {
1139                throw new OozieCLIException(ex.toString(), ex);
1140            }
1141        }
1142    
1143        private void versionCommand() throws OozieCLIException {
1144            System.out.println("Oozie client build version: "
1145                    + BuildInfo.getBuildInfo().getProperty(BuildInfo.BUILD_VERSION));
1146        }
1147    
1148        private void printJobs(List<WorkflowJob> jobs, boolean localtime, boolean verbose) throws IOException {
1149            if (jobs != null && jobs.size() > 0) {
1150                if (verbose) {
1151                    System.out.println("Job ID" + VERBOSE_DELIMITER + "App Name" + VERBOSE_DELIMITER + "App Path"
1152                            + VERBOSE_DELIMITER + "Console URL" + VERBOSE_DELIMITER + "User" + VERBOSE_DELIMITER + "Group"
1153                            + VERBOSE_DELIMITER + "Run" + VERBOSE_DELIMITER + "Created" + VERBOSE_DELIMITER + "Started"
1154                            + VERBOSE_DELIMITER + "Status" + VERBOSE_DELIMITER + "Last Modified" + VERBOSE_DELIMITER
1155                            + "Ended");
1156                    System.out.println(RULER);
1157    
1158                    for (WorkflowJob job : jobs) {
1159                        System.out.println(maskIfNull(job.getId()) + VERBOSE_DELIMITER + maskIfNull(job.getAppName())
1160                                + VERBOSE_DELIMITER + maskIfNull(job.getAppPath()) + VERBOSE_DELIMITER
1161                                + maskIfNull(job.getConsoleUrl()) + VERBOSE_DELIMITER + maskIfNull(job.getUser())
1162                                + VERBOSE_DELIMITER + maskIfNull(job.getGroup()) + VERBOSE_DELIMITER + job.getRun()
1163                                + VERBOSE_DELIMITER + maskDate(job.getCreatedTime(), localtime) + VERBOSE_DELIMITER
1164                                + maskDate(job.getStartTime(), localtime) + VERBOSE_DELIMITER + job.getStatus()
1165                                + VERBOSE_DELIMITER + maskDate(job.getLastModifiedTime(), localtime) + VERBOSE_DELIMITER
1166                                + maskDate(job.getEndTime(), localtime));
1167    
1168                        System.out.println(RULER);
1169                    }
1170                }
1171                else {
1172                    System.out.println(String.format(WORKFLOW_JOBS_FORMATTER, "Job ID", "App Name", "Status", "User",
1173                            "Group", "Started", "Ended"));
1174                    System.out.println(RULER);
1175    
1176                    for (WorkflowJob job : jobs) {
1177                        System.out.println(String.format(WORKFLOW_JOBS_FORMATTER, maskIfNull(job.getId()), maskIfNull(job
1178                                .getAppName()), job.getStatus(), maskIfNull(job.getUser()), maskIfNull(job.getGroup()),
1179                                maskDate(job.getStartTime(), localtime), maskDate(job.getEndTime(), localtime)));
1180    
1181                        System.out.println(RULER);
1182                    }
1183                }
1184            }
1185            else {
1186                System.out.println("No Jobs match your criteria!");
1187            }
1188        }
1189    
1190        private String maskIfNull(String value) {
1191            if (value != null && value.length() > 0) {
1192                return value;
1193            }
1194            return "-";
1195        }
1196    
1197        private String maskDate(Date date, boolean isLocalTimeZone) {
1198            if (date == null) {
1199                return "-";
1200            }
1201    
1202            // SimpleDateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd
1203            // HH:mm Z", Locale.US);
1204            SimpleDateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US);
1205            if (!isLocalTimeZone) {
1206                dateFormater.setTimeZone(TimeZone.getTimeZone("GMT"));
1207            }
1208            return dateFormater.format(date);
1209        }
1210    
1211        private void validateCommand(CommandLine commandLine) throws OozieCLIException {
1212            String[] args = commandLine.getArgs();
1213            if (args.length != 1) {
1214                throw new OozieCLIException("One file must be specified");
1215            }
1216            File file = new File(args[0]);
1217            if (file.exists()) {
1218                try {
1219                    List<StreamSource> sources = new ArrayList<StreamSource>();
1220                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1221                            "oozie-workflow-0.1.xsd")));
1222                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1223                            "email-action-0.1.xsd")));
1224                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1225                            "distcp-action-0.1.xsd")));
1226                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1227                            "oozie-workflow-0.2.xsd")));
1228                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1229                            "oozie-workflow-0.2.5.xsd")));
1230                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1231                            "oozie-workflow-0.3.xsd")));
1232                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1233                            "oozie-coordinator-0.1.xsd")));
1234                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1235                            "oozie-coordinator-0.2.xsd")));
1236                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1237                            "oozie-coordinator-0.3.xsd")));
1238                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1239                            "oozie-bundle-0.1.xsd")));
1240                    sources.add(new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(
1241                            "oozie-sla-0.1.xsd")));
1242                    SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
1243                    Schema schema = factory.newSchema(sources.toArray(new StreamSource[sources.size()]));
1244                    Validator validator = schema.newValidator();
1245                    validator.validate(new StreamSource(new FileReader(file)));
1246                    System.out.println("Valid worflow-app");
1247                }
1248                catch (Exception ex) {
1249                    throw new OozieCLIException("Invalid workflow-app, " + ex.toString(), ex);
1250                }
1251            }
1252            else {
1253                throw new OozieCLIException("File does not exists");
1254            }
1255        }
1256    
1257        private void pigCommand(CommandLine commandLine) throws IOException, OozieCLIException {
1258            List<String> pigArgs = commandLine.getArgList();
1259            if (pigArgs.size() > 0) {
1260                // checking is a pigArgs starts with -X (because CLIParser cannot check this)
1261                if (!pigArgs.get(0).equals("-X")) {
1262                    throw new OozieCLIException("Unrecognized option: " + pigArgs.get(0) + " Expecting -X");
1263                }
1264                pigArgs.remove(0);
1265            }
1266    
1267            List<String> options = new ArrayList<String>();
1268            for (Option option : commandLine.getOptions()) {
1269                options.add(option.getOpt());
1270            }
1271    
1272            if (!options.contains(PIGFILE_OPTION)) {
1273                throw new OozieCLIException("Need to specify -file <scriptfile>");
1274            }
1275    
1276            if (!options.contains(CONFIG_OPTION)) {
1277                throw new OozieCLIException("Need to specify -config <configfile>");
1278            }
1279    
1280            Properties conf = getConfiguration(commandLine);
1281            String script = commandLine.getOptionValue(PIGFILE_OPTION);
1282    
1283            try {
1284                XOozieClient wc = createXOozieClient(commandLine);
1285                System.out.println(JOB_ID_PREFIX + wc.submitPig(conf, script, pigArgs.toArray(new String[pigArgs.size()])));
1286            }
1287            catch (OozieClientException ex) {
1288                throw new OozieCLIException(ex.toString(), ex);
1289            }
1290        }
1291    }