001: /*
002: * BatchRunner.java
003: *
004: * This file is part of SQL Workbench/J, http://www.sql-workbench.net
005: *
006: * Copyright 2002-2008, Thomas Kellerer
007: * No part of this code maybe reused without the permission of the author
008: *
009: * To contact the author please send an email to: support@sql-workbench.net
010: *
011: */
012: package workbench.sql;
013:
014: import java.io.File;
015: import java.io.FileNotFoundException;
016: import java.io.IOException;
017: import java.io.PrintStream;
018: import java.io.UnsupportedEncodingException;
019: import java.sql.SQLException;
020: import java.util.List;
021: import workbench.AppArguments;
022: import workbench.db.ConnectionMgr;
023: import workbench.db.ConnectionProfile;
024: import workbench.db.WbConnection;
025: import workbench.gui.components.ConsoleStatusBar;
026: import workbench.gui.components.GenericRowMonitor;
027: import workbench.gui.profiles.ProfileKey;
028: import workbench.interfaces.ParameterPrompter;
029: import workbench.interfaces.ResultLogger;
030: import workbench.interfaces.StatementRunner;
031: import workbench.log.LogMgr;
032: import workbench.resource.ResourceMgr;
033: import workbench.resource.Settings;
034: import workbench.storage.DataPrinter;
035: import workbench.storage.DataStore;
036: import workbench.storage.RowActionMonitor;
037: import workbench.util.ArgumentParser;
038: import workbench.util.EncodingUtil;
039: import workbench.util.ExceptionUtil;
040: import workbench.util.FileDialogUtil;
041: import workbench.util.SqlUtil;
042: import workbench.util.StringUtil;
043: import workbench.util.WbFile;
044:
045: /**
046: * A class to run several statements from a script file.
047: * This is used when running SQL Workbench in batch mode and
048: * for the {@link workbench.sql.wbcommands.WbInclude} command.
049: *
050: * @author support@sql-workbench.net
051: */
052: public class BatchRunner {
053: public static final String CMD_LINE_PROFILE_NAME = "WbCommandLineProfile";
054: private List<String> filenames;
055: private StatementRunner stmtRunner;
056: private WbConnection connection;
057: private boolean abortOnError = false;
058: private String successScript;
059: private String errorScript;
060: private DelimiterDefinition delimiter = null;
061: private boolean showResultSets = false;
062: private boolean showTiming = true;
063: private boolean success = true;
064: private ConnectionProfile profile;
065: private ResultLogger resultDisplay;
066: private boolean cancelExecution = false;
067: private RowActionMonitor rowMonitor;
068: private boolean verboseLogging = true;
069: private boolean checkEscapedQuotes = false;
070: private String encoding = null;
071: private boolean showProgress = false;
072: private PrintStream console = System.out;
073: private boolean quiet = false;
074: private boolean consolidateMessages = false;
075:
076: public BatchRunner(String aFilelist) {
077: this .filenames = StringUtil.stringToList(aFilelist, ",", true);
078: this .stmtRunner = StatementRunner.Factory.createRunner();
079: this .stmtRunner.setFullErrorReporting(true);
080: }
081:
082: /**
083: * The baseDir is used when including other scripts using WbInclude.
084: *
085: * If the filename of the included script is a relative filename
086: * then the StatementRunner will assume the script is located relative
087: * to the baseDir. This call is delegated to
088: * {@link StatementRunner#setBaseDir(String)}
089: *
090: * @param dir the base directory to be used
091: * @see StatementRunner#setBaseDir(String)
092: */
093: public void setBaseDir(String dir) {
094: this .stmtRunner.setBaseDir(dir);
095: }
096:
097: public WbConnection getConnection() {
098: return this .connection;
099: }
100:
101: public void setParameterPrompter(ParameterPrompter p) {
102: this .stmtRunner.setParameterPrompter(p);
103: }
104:
105: /**
106: * For testing purposes to redirect the output to a file
107: */
108: void setConsole(PrintStream output) {
109: this .console = output;
110: }
111:
112: public void showResultSets(boolean flag) {
113: this .showResultSets = flag;
114: }
115:
116: public void setVerboseLogging(boolean flag) {
117: this .verboseLogging = flag;
118: this .stmtRunner.setVerboseLogging(flag);
119: this .showTiming = this .verboseLogging;
120: }
121:
122: public void setConsolidateLog(boolean flag) {
123: this .consolidateMessages = flag;
124: }
125:
126: public void setIgnoreDropErrors(boolean flag) {
127: this .stmtRunner.setIgnoreDropErrors(flag);
128: }
129:
130: public void setProfile(ConnectionProfile aProfile) {
131: this .profile = aProfile;
132: }
133:
134: public DelimiterDefinition getDelimiter() {
135: return this .delimiter;
136: }
137:
138: public void setDelimiter(DelimiterDefinition delim) {
139: if (delim != null)
140: this .delimiter = delim;
141: }
142:
143: public void setConnection(WbConnection conn) {
144: this .connection = conn;
145: this .stmtRunner.setConnection(this .connection);
146: }
147:
148: public boolean isConnected() {
149: return this .connection != null;
150: }
151:
152: public void connect() throws SQLException, ClassNotFoundException {
153: this .connection = null;
154:
155: if (this .profile == null) {
156: // Allow batch runs without a profile for e.g. running a single WbCopy
157: LogMgr
158: .logWarning("BatchRunner.connect()",
159: "No profile defined, proceeding without a connection.");
160: success = true;
161: return;
162: }
163:
164: try {
165: ConnectionMgr mgr = ConnectionMgr.getInstance();
166: WbConnection c = mgr.getConnection(this .profile,
167: "BatchRunner");
168:
169: this .setConnection(c);
170: String info = c.getDisplayString();
171: LogMgr.logInfo("BatchRunner.connect()", ResourceMgr
172: .getFormattedString("MsgBatchConnectOk", c
173: .getDisplayString()));
174: if (!quiet)
175: this .printMessage(ResourceMgr.getFormattedString(
176: "MsgBatchConnectOk", info));
177: success = true;
178: String warn = c.getWarnings();
179: if (!StringUtil.isEmptyString(warn)) {
180: printMessage(warn);
181: LogMgr.logWarning("BatchRunner.connect()",
182: "Connection returned warnings: " + warn);
183: }
184: } catch (ClassNotFoundException e) {
185: String error = ResourceMgr.getString("ErrDriverNotFound");
186: error = StringUtil.replace(error, "%class%", profile
187: .getDriverclass());
188: LogMgr.logError("BatchRunner.connect()", error, null);
189: printMessage(error);
190: success = false;
191: throw e;
192: } catch (SQLException e) {
193: success = false;
194: String msg = ResourceMgr.getString("MsgBatchConnectError")
195: + ": " + ExceptionUtil.getDisplay(e);
196: LogMgr.logError("BatchRunner.connect()", msg, LogMgr
197: .isDebugEnabled() ? e : null);
198: printMessage(msg);
199: throw e;
200: }
201: }
202:
203: public boolean isSuccess() {
204: return this .success;
205: }
206:
207: public void setSuccessScript(String aFilename) {
208: if (aFilename == null)
209: return;
210: File f = new File(aFilename);
211: if (f.exists() && !f.isDirectory()) {
212: this .successScript = aFilename;
213: } else {
214: this .successScript = null;
215: }
216: }
217:
218: public void setErrorScript(String aFilename) {
219: if (aFilename == null)
220: return;
221: File f = new File(aFilename);
222: if (f.exists() && !f.isDirectory()) {
223: this .errorScript = aFilename;
224: } else {
225: this .errorScript = null;
226: }
227: }
228:
229: public void setRowMonitor(RowActionMonitor mon) {
230: this .rowMonitor = mon;
231: this .stmtRunner.setRowMonitor(this .rowMonitor);
232: }
233:
234: public void execute() {
235: boolean error = false;
236: int count = this .filenames.size();
237:
238: if (this .rowMonitor != null) {
239: this .rowMonitor
240: .setMonitorType(RowActionMonitor.MONITOR_PROCESS);
241: }
242:
243: int currentFileIndex = 0;
244:
245: for (String file : filenames) {
246: currentFileIndex++;
247:
248: WbFile fo = new WbFile(file);
249:
250: if (this .rowMonitor != null) {
251: this .rowMonitor.setCurrentObject(file,
252: currentFileIndex, count);
253: this .rowMonitor.saveCurrentType("batchrunnerMain");
254: }
255:
256: try {
257: String msg = ResourceMgr
258: .getString("MsgBatchProcessingFile")
259: + " " + fo.getFullPath();
260: LogMgr.logInfo("BatchRunner.execute()", msg);
261: if (this .resultDisplay != null) {
262: this .resultDisplay.appendToLog(msg);
263: this .resultDisplay.appendToLog("\n");
264: }
265: String dir = fo.getCanonicalFile().getParent();
266: this .setBaseDir(dir);
267:
268: error = this .executeScript(fo);
269: } catch (Exception e) {
270: error = true;
271: LogMgr.logError("BatchRunner.execute()", ResourceMgr
272: .getString("MsgBatchScriptFileError")
273: + " " + file, e);
274: String msg = null;
275:
276: if (e instanceof FileNotFoundException) {
277: msg = ResourceMgr.getFormattedString(
278: "ErrFileNotFound", file);
279: } else {
280: msg = e.getMessage();
281: }
282: if (showProgress)
283: printMessage("\n"); // force newline in case progress reporting was turned on
284: printMessage(ResourceMgr.getString("TxtError") + ": "
285: + msg);
286: }
287: if (error && abortOnError) {
288: break;
289: }
290: }
291:
292: if (abortOnError && error) {
293: this .success = false;
294: try {
295: if (this .errorScript != null) {
296: WbFile f = new WbFile(errorScript);
297: LogMgr.logInfo("BatchRunner", ResourceMgr
298: .getString("MsgBatchExecutingErrorScript")
299: + " " + f.getFullPath());
300: this .executeScript(f);
301: }
302: } catch (Exception e) {
303: LogMgr.logError("BatchRunner.execute()", ResourceMgr
304: .getString("MsgBatchScriptFileError")
305: + " " + this .errorScript, e);
306: }
307: } else {
308: this .success = true;
309: try {
310: if (this .successScript != null) {
311: WbFile f = new WbFile(successScript);
312: LogMgr
313: .logInfo(
314: "BatchRunner",
315: ResourceMgr
316: .getString("MsgBatchExecutingSuccessScript")
317: + " " + f.getFullPath());
318: this .executeScript(f);
319: }
320: } catch (Exception e) {
321: LogMgr.logError("BatchRunner.execute()", ResourceMgr
322: .getString("MsgBatchScriptFileError")
323: + " " + this .successScript, e);
324: }
325: }
326: }
327:
328: public void cancel() {
329: this .cancelExecution = true;
330: if (this .stmtRunner != null) {
331: this .stmtRunner.cancel();
332: }
333: }
334:
335: private boolean executeScript(WbFile scriptFile) throws IOException {
336: boolean error = false;
337: ScriptParser parser = new ScriptParser();
338: DelimiterDefinition altDelim = null;
339:
340: // If no delimiter has been defined, than use the default fallback
341: if (this .delimiter == null) {
342: altDelim = Settings.getInstance().getAlternateDelimiter(
343: this .connection);
344: parser.setDelimiters(
345: DelimiterDefinition.STANDARD_DELIMITER, altDelim);
346: } else {
347: // if a delimiter has been defined, then use only this
348: parser.setDelimiters(this .delimiter, null);
349: }
350:
351: // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11
352: // The connection might not be initialized!
353: // When running a single WbCopy command it is not necessary to define a
354: // connection on the commandline
355: // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
356: if (this .connection != null) {
357: parser.setSupportOracleInclude(this .connection
358: .getDbSettings().supportSingleLineCommands());
359: parser.setCheckForSingleLineCommands(this .connection
360: .getDbSettings().supportShortInclude());
361: parser.setAlternateLineComment(this .connection
362: .getDbSettings().getLineComment());
363: }
364:
365: parser.setCheckEscapedQuotes(this .checkEscapedQuotes);
366: parser.setFile(scriptFile, this .encoding);
367: String sql = null;
368: this .cancelExecution = false;
369:
370: int executedCount = 0;
371: long start, end;
372:
373: final int interval;
374: if (scriptFile.length() < 50000) {
375: interval = 1;
376: } else if (scriptFile.length() < 100000) {
377: interval = 10;
378: } else {
379: interval = 100;
380: }
381:
382: start = System.currentTimeMillis();
383:
384: parser.startIterator();
385: long totalRows = 0;
386: long successCount = 0;
387: long errorCount = 0;
388:
389: while (parser.hasNext()) {
390: sql = parser.getNextCommand();
391: if (sql == null)
392: continue;
393:
394: try {
395: if (this .resultDisplay == null) {
396: LogMgr.logDebug("BatchRunner", ResourceMgr
397: .getString("MsgBatchExecutingStatement")
398: + ": " + sql);
399: }
400:
401: long verbstart = System.currentTimeMillis();
402: this .stmtRunner.runStatement(sql, 0, -1);
403: long verbend = System.currentTimeMillis();
404:
405: error = false;
406:
407: StatementRunnerResult result = this .stmtRunner
408: .getResult();
409:
410: if (result != null) {
411: error = !result.isSuccess();
412:
413: // We have to store the result of hasMessages()
414: // as the getMessageBuffer() will clear the buffer
415: // and a subsequent call to hasMessages() will return false;
416: boolean hasMessage = result.hasMessages();
417: String feedback = result.getMessageBuffer()
418: .toString();
419:
420: if (error) {
421: LogMgr.logError("BatchRunner.execute()",
422: feedback, null);
423: errorCount++;
424: } else {
425: if (result.hasWarning())
426: LogMgr.logWarning("BatchRunner.execute()",
427: feedback);
428: successCount++;
429: totalRows += result.getTotalUpdateCount();
430: }
431:
432: if (hasMessage
433: && (this .stmtRunner.getVerboseLogging() || error)) {
434: if (!this .consolidateMessages) {
435: this .printMessage("\n" + feedback);
436: }
437: } else if (result.hasWarning()) {
438: String verb = SqlUtil.getSqlVerb(sql);
439: String msg = StringUtil.replace(ResourceMgr
440: .getString("MsgStmtCompletedWarn"),
441: "%verb%", verb);
442: this .printMessage("\n" + msg);
443: }
444: executedCount++;
445: }
446:
447: if (this .showTiming && !consolidateMessages) {
448: this
449: .printMessage(ResourceMgr
450: .getString("MsgSqlVerbTime")
451: + " "
452: + (((double) (verbend - verbstart)) / 1000.0)
453: + "s");
454: }
455:
456: if (this .rowMonitor != null
457: && (executedCount % interval == 0)) {
458: this .rowMonitor.restoreType("batchrunnerMain");
459: this .rowMonitor.setCurrentRow(executedCount, -1);
460: }
461:
462: if (this .cancelExecution) {
463: if (!quiet)
464: this .printMessage(ResourceMgr
465: .getString("MsgStatementCancelled"));
466: break;
467: }
468:
469: printResults(sql, result);
470: } catch (Exception e) {
471: LogMgr.logError("BatchRunner", ResourceMgr
472: .getString("MsgBatchStatementError")
473: + " " + sql, e);
474: printMessage(ExceptionUtil.getDisplay(e));
475: error = true;
476: break;
477: }
478: if (error && abortOnError)
479: break;
480: }
481:
482: end = System.currentTimeMillis();
483:
484: StringBuilder msg = new StringBuilder(50);
485: msg.append(scriptFile.getFullPath());
486: msg.append(": ");
487: msg.append(executedCount);
488: msg.append(' ');
489: msg.append(ResourceMgr.getString("MsgTotalStatementsExecuted"));
490: if (resultDisplay == null)
491: msg.insert(0, '\n'); // force newline on console
492: this .printMessage(msg.toString());
493:
494: if (consolidateMessages) {
495: if (errorCount > 0) {
496: printMessage((resultDisplay == null ? "\n" : "")
497: + errorCount
498: + " "
499: + ResourceMgr
500: .getString("MsgTotalStatementsFailed"));
501: }
502: this .printMessage(totalRows + " "
503: + ResourceMgr.getString("MsgTotalRowsAffected"));
504: }
505:
506: parser.done();
507:
508: if (this .showTiming) {
509: long execTime = (end - start);
510: String m = ResourceMgr.getString("MsgExecTime") + " "
511: + (((double) execTime) / 1000.0) + "s";
512: this .printMessage(m);
513: }
514:
515: return error;
516: }
517:
518: private void printResults(String sql, StatementRunnerResult result) {
519: if (console == null)
520: return;
521: if (result == null)
522: return;
523: if (!this .showResultSets)
524: return;
525: if (!result.isSuccess())
526: return;
527:
528: console.println();
529: console.println(sql);
530: console.println("---------------- "
531: + ResourceMgr.getString("MsgResultLogStart")
532: + " ----------------------------");
533: List<DataStore> data = result.getDataStores();
534: for (DataStore ds : data) {
535: DataPrinter printer = new DataPrinter(ds);
536: printer.printTo(console);
537: }
538: console.println("---------------- "
539: + ResourceMgr.getString("MsgResultLogEnd")
540: + " ----------------------------");
541: }
542:
543: public void setEncoding(String enc)
544: throws UnsupportedEncodingException {
545: if (enc == null) {
546: this .encoding = null;
547: } else {
548: if (!EncodingUtil.isEncodingSupported(enc))
549: throw new UnsupportedEncodingException(enc
550: + " encoding not supported!");
551: this .encoding = EncodingUtil.cleanupEncoding(enc);
552: }
553: }
554:
555: public void setShowTiming(boolean flag) {
556: this .showTiming = flag;
557: }
558:
559: public void setAbortOnError(boolean aFlag) {
560: this .abortOnError = aFlag;
561: }
562:
563: public void setCheckEscapedQuotes(boolean flag) {
564: this .checkEscapedQuotes = flag;
565: }
566:
567: public void setResultLogger(ResultLogger logger) {
568: this .resultDisplay = logger;
569: if (this .stmtRunner != null) {
570: this .stmtRunner.setResultLogger(logger);
571: }
572: }
573:
574: private void printMessage(String msg) {
575: if (this .resultDisplay == null) {
576: if (msg != null && msg.length() > 0)
577: System.out.println(msg);
578: } else {
579: this .resultDisplay.appendToLog(msg);
580: this .resultDisplay.appendToLog("\n");
581: }
582: }
583:
584: public static ConnectionProfile createCmdLineProfile(
585: ArgumentParser cmdLine) {
586: ConnectionProfile result = null;
587: if (!cmdLine.isArgPresent(AppArguments.ARG_CONN_URL))
588: return null;
589: try {
590: String url = cmdLine.getValue(AppArguments.ARG_CONN_URL);
591: if (url == null) {
592: LogMgr
593: .logError(
594: "BatchRunner.createCmdLineProfile()",
595: "Cannot connect with command line settings without a connection URL!",
596: null);
597: return null;
598: }
599: String driverclass = cmdLine
600: .getValue(AppArguments.ARG_CONN_DRIVER);
601: if (driverclass == null) {
602: LogMgr
603: .logError(
604: "BatchRunner.createCmdLineProfile()",
605: "Cannot connect with command line settings without a driver class!",
606: null);
607: return null;
608: }
609: String user = cmdLine.getValue(AppArguments.ARG_CONN_USER);
610: String pwd = cmdLine.getValue(AppArguments.ARG_CONN_PWD);
611: String jar = cmdLine.getValue(AppArguments.ARG_CONN_JAR);
612: String commit = cmdLine
613: .getValue(AppArguments.ARG_CONN_AUTOCOMMIT);
614: String wksp = cmdLine.getValue(AppArguments.ARG_WORKSPACE);
615: String delimDef = cmdLine
616: .getValue(AppArguments.ARG_ALT_DELIMITER);
617: DelimiterDefinition delim = DelimiterDefinition
618: .parseCmdLineArgument(delimDef);
619: boolean trimCharData = cmdLine.getBoolean(
620: AppArguments.ARG_CONN_TRIM_CHAR, false);
621: boolean rollback = cmdLine.getBoolean(
622: AppArguments.ARG_CONN_ROLLBACK, false);
623:
624: if (jar != null) {
625: ConnectionMgr.getInstance().registerDriver(driverclass,
626: jar);
627: }
628:
629: result = new ConnectionProfile(CMD_LINE_PROFILE_NAME,
630: driverclass, url, user, pwd);
631: result.setRollbackBeforeDisconnect(rollback);
632: result.setAlternateDelimiter(delim);
633: result.setTrimCharData(trimCharData);
634: if (!StringUtil.isEmptyString(wksp)) {
635: wksp = FileDialogUtil.replaceConfigDir(wksp);
636: File f = new File(wksp);
637: if (!f.exists() && !f.isAbsolute()) {
638: f = new File(Settings.getInstance().getConfigDir(),
639: wksp);
640: }
641: if (f.exists()) {
642: result.setWorkspaceFile(f.getAbsolutePath());
643: }
644: }
645: if (!StringUtil.isEmptyString(commit)) {
646: result.setAutocommit(StringUtil.stringToBool(commit));
647: }
648: } catch (Exception e) {
649: LogMgr.logError("BatchRunner.initFromCommandLine()",
650: "Error creating temporary profile", e);
651: result = null;
652: }
653: return result;
654: }
655:
656: public static BatchRunner createBatchRunner(ArgumentParser cmdLine) {
657: String scripts = cmdLine.getValue(AppArguments.ARG_SCRIPT);
658: if (scripts == null || scripts.trim().length() == 0)
659: return null;
660:
661: String profilename = cmdLine.getValue(AppArguments.ARG_PROFILE);
662:
663: boolean abort = cmdLine
664: .getBoolean(AppArguments.ARG_ABORT, true);
665: boolean showResult = cmdLine
666: .getBoolean(AppArguments.ARG_DISPLAY_RESULT);
667: boolean showProgress = cmdLine.getBoolean(
668: AppArguments.ARG_SHOWPROGRESS, false);
669: boolean consolidateLog = cmdLine.getBoolean(
670: AppArguments.ARG_CONSOLIDATE_LOG, false);
671: String encoding = cmdLine
672: .getValue(AppArguments.ARG_SCRIPT_ENCODING);
673:
674: ConnectionProfile profile = null;
675: if (profilename == null) {
676: profile = createCmdLineProfile(cmdLine);
677: } else {
678: String group = cmdLine
679: .getValue(AppArguments.ARG_PROFILE_GROUP);
680: ProfileKey def = new ProfileKey(StringUtil
681: .trimQuotes(profilename), StringUtil
682: .trimQuotes(group));
683:
684: profile = ConnectionMgr.getInstance().getProfile(def);
685: if (profile == null) {
686: String msg = "Profile [" + def + "] not found!";
687: System.err.println(msg);
688: LogMgr.logError("BatchRunner.initFromCommandLine", msg,
689: null);
690: return null;
691: }
692: }
693:
694: if (profile != null) {
695: boolean ignoreDrop = cmdLine.getBoolean(
696: AppArguments.ARG_IGNORE_DROP, true);
697: profile.setIgnoreDropErrors(ignoreDrop);
698: }
699:
700: String success = cmdLine
701: .getValue(AppArguments.ARG_SUCCESS_SCRIPT);
702: String error = cmdLine.getValue(AppArguments.ARG_ERROR_SCRIPT);
703: String feed = cmdLine.getValue(AppArguments.ARG_FEEDBACK);
704: boolean feedback = cmdLine.getBoolean(
705: AppArguments.ARG_FEEDBACK, true);
706:
707: BatchRunner runner = new BatchRunner(scripts);
708: runner.showResultSets(showResult);
709: try {
710: runner.setEncoding(encoding);
711: } catch (Exception e) {
712: LogMgr.logError("BatchRunner.createBatchRunner()",
713: "Invalid encoding '" + encoding
714: + "' specified. Using platform default'",
715: null);
716: }
717:
718: runner.setAbortOnError(abort);
719: runner.setErrorScript(error);
720: runner.setSuccessScript(success);
721: runner.setProfile(profile);
722: runner.setVerboseLogging(feedback);
723: runner.setConsolidateLog(consolidateLog);
724: runner.quiet = cmdLine.isArgPresent(AppArguments.ARG_QUIET);
725:
726: // if no showTiming argument was provided but feedback was disabled
727: // disable the display of the timing information as well.
728: String tim = cmdLine.getValue(AppArguments.ARG_SHOW_TIMING);
729: if (tim == null && feed != null && !feedback) {
730: runner.showTiming = false;
731: } else {
732: runner.showTiming = cmdLine.getBoolean(
733: AppArguments.ARG_SHOW_TIMING, true);
734: }
735: runner.showProgress = showProgress;
736: if (showProgress) {
737: runner.setRowMonitor(new GenericRowMonitor(
738: new ConsoleStatusBar()));
739: }
740:
741: DelimiterDefinition delim = DelimiterDefinition
742: .parseCmdLineArgument(cmdLine
743: .getValue(AppArguments.ARG_DELIMITER));
744:
745: if (delim != null) {
746: runner.setDelimiter(delim);
747: }
748:
749: return runner;
750: }
751: }
|