001: /*
002: * This file or a portion of this file is licensed under the terms of
003: * the Globus Toolkit Public License, found in file GTPL, or at
004: * http://www.globus.org/toolkit/download/license.html. This notice must
005: * appear in redistributions of this file, with or without modification.
006: *
007: * Redistributions of this Software, with or without modification, must
008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
009: * some other similar material which is provided with the Software (if
010: * any).
011: *
012: * Copyright 1999-2004 University of Chicago and The University of
013: * Southern California. All rights reserved.
014: */
015: package org.griphyn.vdl.toolkit;
016:
017: import java.io.*;
018: import java.sql.SQLException;
019: import java.util.Iterator;
020: import java.util.Date;
021: import java.util.List;
022: import java.util.ArrayList;
023:
024: import org.griphyn.common.util.Version;
025: import org.griphyn.common.util.Currently;
026: import org.griphyn.vdl.parser.InvocationParser;
027: import org.griphyn.vdl.invocation.*;
028: import org.griphyn.vdl.dbschema.*;
029: import org.griphyn.vdl.util.Logging;
030: import org.griphyn.vdl.util.ChimeraProperties;
031: import org.griphyn.vdl.directive.*;
032: import gnu.getopt.*;
033:
034: /**
035: * This class gets the exit code of a job from invocation record.
036: *
037: * @author Jens-S. Vöckler
038: * @author Yong Zhao
039: * @version $Revision: 50 $
040: *
041: * @see org.griphyn.vdl.parser.InvocationParser
042: * @see org.griphyn.vdl.dbschema.DatabaseSchema
043: */
044: public class ExitCode extends Toolkit {
045: /**
046: * Just a string to denote the short usage.
047: */
048: public static final String m_usage1 = "[-d dbprefix | -n | -N] [-e] [-f] [-i] [-v] [-l tag -m ISO] file [..]";
049:
050: /**
051: * ctor: Constructs a new instance object with the given application name.
052: */
053: public ExitCode(String appName) {
054: super (appName);
055: }
056:
057: /**
058: * Implements printing the usage string onto stdout.
059: */
060: public void showUsage() {
061: String linefeed = System.getProperty("line.separator", "\r\n");
062:
063: System.out
064: .println("$Id: ExitCode.java 50 2007-05-19 00:48:32Z gmehta $"
065: + linefeed
066: + "VDS version "
067: + Version.instance().toString() + linefeed);
068:
069: System.out.println("Usage: " + this .m_application + ' '
070: + m_usage1);
071: System.out
072: .println(linefeed
073: + "Generic options: "
074: + linefeed
075: + " -d|--dbase dbx associates the dbname with the database, unused."
076: + linefeed
077: + " -V|--version print version information and exit."
078: + linefeed
079: + " -v|--verbose verbose mode, switches on property vds.log.app on stdout."
080: + linefeed
081: + " -i|--ignore ignore exit code for failure, just add to database."
082: + linefeed
083: + " -n|--noadd extract the exit code, don\'t add to any database."
084: + linefeed
085: + " -N|--nofail extract and add, but do not fail on db errors."
086: + linefeed
087: + " -e|--emptyfail takes empty files to mean failure instead of ok."
088: + linefeed
089: + " -f|--fail stops parsing on the first error found instead of going on."
090: + linefeed
091: + " -l|--label tag attaches the tag string (32 char max) to all records."
092: + linefeed
093: + " -m|--mtime ISO uses the ISO 8601 timestamp as WF mtime for all records."
094: + linefeed
095: + " Options -l and -m must be used in conjunction!"
096: + linefeed
097: + linefeed
098: + "The following exit codes are returned (except in -i mode):"
099: + linefeed
100: + " 0 remote application ran to conclusion with exit code zero."
101: + linefeed
102: + " 1 remote application concluded with a non-zero exit code."
103: + linefeed
104: + " 2 kickstart failed to start the remote application."
105: + linefeed
106: + " 3 remote application died on a signal, check database."
107: + linefeed
108: + " 4 remote application was suspended, should not happen."
109: + linefeed
110: + " 5 invocation record has an invalid state, unable to parse."
111: + linefeed
112: + " 6 illegal state, inform vds-support@griphyn.org."
113: + linefeed
114: + " 7 illegal state, stumbled over an exception, try --verbose for details"
115: + linefeed
116: + " 8 multiple 0..5 failures during parsing of multiple records"
117: + linefeed);
118: }
119:
120: /**
121: * Creates a set of options.
122: */
123: protected LongOpt[] generateValidOptions() {
124: LongOpt[] lo = new LongOpt[11];
125:
126: lo[0] = new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h');
127: lo[1] = new LongOpt("dbase", LongOpt.REQUIRED_ARGUMENT, null,
128: 'd');
129: lo[2] = new LongOpt("version", LongOpt.NO_ARGUMENT, null, 'V');
130: lo[3] = new LongOpt("verbose", LongOpt.NO_ARGUMENT, null, 'v');
131:
132: lo[4] = new LongOpt("ignore", LongOpt.NO_ARGUMENT, null, 'i');
133: lo[5] = new LongOpt("noadd", LongOpt.NO_ARGUMENT, null, 'n');
134: lo[6] = new LongOpt("nofail", LongOpt.NO_ARGUMENT, null, 'N');
135:
136: lo[7] = new LongOpt("emptyfail", LongOpt.NO_ARGUMENT, null, 'e');
137: lo[8] = new LongOpt("fail", LongOpt.NO_ARGUMENT, null, 'f');
138: lo[9] = new LongOpt("label", LongOpt.REQUIRED_ARGUMENT, null,
139: 'l');
140: lo[10] = new LongOpt("mtime", LongOpt.REQUIRED_ARGUMENT, null,
141: 'm');
142:
143: return lo;
144: }
145:
146: public void showThreads() {
147: ThreadGroup tg = Thread.currentThread().getThreadGroup();
148: while (tg.getParent() != null)
149: tg = tg.getParent();
150: tg.list();
151: }
152:
153: public static void main(String[] args) {
154: int result = 0;
155: int verbose = 0;
156: ExitCode me = null;
157: boolean noDBase = false;
158: boolean ignoreDBFail = false;
159:
160: boolean failOver = true;
161: boolean emptyFail = false;
162: boolean earlyFail = false;
163: ParseKickstart pks = null;
164:
165: String wf_label = null;
166: Date wf_mtime = null;
167: int wf_flag = 0;
168:
169: try {
170: me = new ExitCode("exitcode");
171: if (args.length == 0) {
172: me.showUsage();
173: return;
174: }
175:
176: // get the commandline options
177: Getopt opts = new Getopt(me.m_application, args,
178: "d:hefil:m:nNvV", me.generateValidOptions());
179: opts.setOpterr(false);
180: int option = 0;
181: while ((option = opts.getopt()) != -1) {
182: switch (option) {
183: case 'V':
184: System.out
185: .println("$Id: ExitCode.java 50 2007-05-19 00:48:32Z gmehta $");
186: System.out.println("VDS version "
187: + Version.instance().toString());
188: return;
189:
190: case 'd':
191: // currently inactive option
192: opts.getOptarg();
193: break;
194:
195: case 'e':
196: emptyFail = true;
197: break;
198:
199: case 'f':
200: earlyFail = true;
201: break;
202:
203: case 'i':
204: failOver = false;
205: break;
206:
207: case 'l':
208: if ((wf_label = opts.getOptarg()) != null) {
209: if (wf_label.length() > 0)
210: wf_flag |= 1;
211: else
212: wf_label = null;
213: }
214: break;
215:
216: case 'm':
217: if ((wf_mtime = Currently.parse(opts.getOptarg())) != null)
218: wf_flag |= 2;
219: break;
220:
221: case 'n':
222: noDBase = true;
223: break;
224:
225: case 'N':
226: ignoreDBFail = true;
227: break;
228:
229: case 'v':
230: verbose = me.increaseVerbosity();
231: break;
232:
233: case '?':
234: System.out.println("Invalid option '"
235: + (char) opts.getOptopt() + "'");
236: default:
237: case 'h':
238: me.showUsage();
239: return;
240: }
241: }
242:
243: // print usage information
244: String arg0 = null;
245: if (opts.getOptind() >= args.length) {
246: System.out.println("missing necessary file argument");
247: me.showUsage();
248: return;
249: }
250:
251: // check for -m and -l
252: if (wf_flag != 0 && wf_flag != 3) {
253: me.m_logger
254: .log("default", 0,
255: "Warning: Options -m and -l should be used together!");
256: }
257: if (wf_label != null && wf_label.length() > 32) {
258: wf_label = wf_label.substring(0, 32);
259: me.m_logger.log("default", 0,
260: "Warning: Truncating workflow label to \""
261: + wf_label + "\"");
262: }
263:
264: ChimeraProperties props = ChimeraProperties.instance();
265: DatabaseSchema dbschema = null;
266: String ptcSchemaName = props.getPTCSchemaName();
267: if (ptcSchemaName == null)
268: noDBase = true;
269: if (!noDBase) {
270: try {
271: Connect connect = new Connect();
272: dbschema = connect.connectDatabase(ptcSchemaName);
273: } catch (Exception e) {
274: if (ignoreDBFail) {
275: // if dbase errors are not fatal, just record the fact
276: String cls = e.getClass().getName();
277: String msg = e.getMessage();
278: if (msg == null) {
279: Throwable t = e.getCause();
280: if (t != null) {
281: cls = t.getClass().getName();
282: msg = t.getMessage();
283: }
284: }
285: me.m_logger.log("default", 0,
286: "While connecting to dbase: " + cls
287: + ": " + msg + ", ignoring");
288: dbschema = null;
289: } else {
290: // re-throw, if dbase errors are fatal (default)
291: throw e;
292: }
293: }
294:
295: // check for invocation record support
296: if (dbschema == null || !(dbschema instanceof PTC)) {
297: me.m_logger.log("default", 0,
298: "Your database cannot store invocation records"
299: + ", assuming -n mode");
300: noDBase = true;
301: }
302: }
303:
304: // instantiate parser
305: pks = new ParseKickstart(dbschema, emptyFail);
306: pks.setNoDBase(noDBase);
307: pks.setIgnoreDBFail(ignoreDBFail);
308: pks.setWorkflowLabel(wf_label); // null ok
309: pks.setWorkflowTimestamp(wf_mtime); // null ok
310: dbschema = null; // decrease reference counter
311:
312: // for all files specified
313: for (int i = opts.getOptind(); i < args.length; ++i) {
314: List l = pks.parseFile(args[i]);
315:
316: // determine result code
317: if (failOver) {
318: for (Iterator j = l.iterator(); j.hasNext();) {
319: int status = ((Integer) j.next()).intValue();
320: me.m_logger.log("app", 1, "exit status = "
321: + status);
322: if (status != 0)
323: result = (result == 0 ? status : 8);
324: }
325: }
326:
327: if (result != 0 && earlyFail)
328: break;
329: } // for
330: } catch (FriendlyNudge fn) {
331: me.m_logger.log("default", 0, fn.getMessage());
332: if (failOver)
333: result = fn.getResult();
334:
335: } catch (Exception e) {
336: String cls = e.getClass().getName();
337: String msg = e.getMessage();
338: if (msg == null) {
339: // another try
340: Throwable t = e.getCause();
341: if (t != null) {
342: msg = t.getMessage();
343: cls = t.getClass().getName();
344: }
345: }
346:
347: if (verbose > 0)
348: e.printStackTrace();
349: System.err.println(cls + ": " + msg);
350: result = 7;
351:
352: } finally {
353: try {
354: if (pks != null)
355: pks.close();
356: } catch (Exception e) {
357: me.m_logger.log("default", 0, "ERROR: "
358: + e.getMessage());
359: }
360: }
361:
362: // Java will return with 0 unless exit is used. Unfortunately, using
363: // System.exit sometimes has some unwanted side-effects on d'tors,
364: // thus avoid using it unless strictly necessary.
365: // me.showThreads();
366: if (result != 0)
367: System.exit(result);
368: }
369: }
|