001 /* 002 * $RCSfile: CommandLineTask.java,v $ 003 * 004 * Created on September 30, 2002, 10:02 AM 005 * 006 * This file is part of the STAR Scheduler. 007 * Copyright (c) 2002-2006 STAR Collaboration - Brookhaven National Laboratory 008 * 009 * STAR Scheduler is free software; you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as published by 011 * the Free Software Foundation; either version 2 of the License, or 012 * (at your option) any later version. 013 * 014 * STAR Scheduler is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public License 020 * along with STAR Scheduler; if not, write to the Free Software 021 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 022 */ 023 package gov.bnl.star.offline.scheduler.util; 024 025 import java.io.*; 026 import java.util.logging.Level; 027 import org.apache.log4j.Logger; 028 029 030 /** A command line task. 031 * Fork and execute programs in separate time limited thread. 032 * @author Gabriele Carcassi 033 * @version $Revision: 1.14 $ $Date: 2006/11/21 00:41:30 $ 034 */ 035 public class CommandLineTask extends Task { 036 static private Logger log = Logger.getLogger(CommandLineTask.class.getName()); 037 private String commandLine; 038 private String[] commandLineArray; 039 private boolean bufferOutput; 040 private String commandOutput; 041 private Process proc; 042 043 /** A new command line task. 044 * <p> 045 * WARNING: the parsing of the command line won't be what you would have while 046 * executing at a UNIX prompt. The command line won't be passed to the shell, 047 * that is why it may have different result. For example, wildcards are usually 048 * resolved by the shell, and not by the program themselves. 049 * @param commandLine the command line to be executed 050 */ 051 public CommandLineTask(String commandLine) { 052 this(commandLine, false); 053 } 054 055 /** A new command line task. This allows you to buffer the output of the command. 056 * You can retrieve the ouput with <CODE>getOutput</CODE> or 057 * <CODE>getOutputReader</CODE> 058 * <p> 059 * WARNING: the parsing of the command line won't be what you would have while 060 * executing at a UNIX prompt. The command line won't be passed to the shell, 061 * that is why it may have different result. For example, wildcards are usually 062 * resolved by the shell, and not by the program themselves. 063 * @param commandLine the command line to be executed 064 * @param bufferCommandOutput if true, the output will be buffered 065 */ 066 public CommandLineTask(String commandLine, boolean bufferCommandOutput) { 067 this.commandLine = commandLine; 068 this.bufferOutput = bufferCommandOutput; 069 } 070 071 /** A new command line task with a timeout. The command will be aborted if the 072 * process doesn't return before the timeout. 073 * <p> 074 * WARNING: the parsing of the command line won't be what you would have while 075 * executing at a UNIX prompt. The command line won't be passed to the shell, 076 * that is why it may have different result. For example, wildcards are usually 077 * resolved by the shell, and not by the program themselves. 078 * @param commandLine 079 * @param msTimeout 080 */ 081 public CommandLineTask(String commandLine, int msTimeout) { 082 super(msTimeout); 083 this.commandLine = commandLine; 084 } 085 086 public CommandLineTask(String commandLine, int msTimeout, boolean bufferCommandOutput) { 087 super(msTimeout); 088 this.commandLine = commandLine; 089 this.bufferOutput = bufferCommandOutput; 090 } 091 092 /** A new command line task. This allows you to buffer the output of the command. 093 * You can retrieve the ouput with <CODE>getOutput</CODE> or 094 * <CODE>getOutputReader</CODE> 095 * <p> 096 * By actually specifying he argument as a String array, this constructor gives 097 * you better control of what is being executed 098 * @param commandLineArray the command line to be executed already parsed in the different arguments 099 * @param bufferCommandOutput if true, the output will be buffered 100 */ 101 public CommandLineTask(String[] commandLineArray, 102 boolean bufferCommandOutput) { 103 this.commandLineArray = commandLineArray; 104 this.bufferOutput = bufferCommandOutput; 105 } 106 107 /** Calls the external command. Don't use this directly, or your task won't be 108 * executed in a separate thread. Use <CODE>execute</CODE> instead. 109 */ 110 public void run() { 111 try { 112 if (commandLine != null) { 113 proc = Runtime.getRuntime().exec(commandLine); 114 } else { 115 proc = Runtime.getRuntime().exec(commandLineArray); 116 } 117 118 if (bufferOutput) { 119 Reader read = new InputStreamReader(proc.getInputStream()); 120 StringWriter write = new StringWriter(); 121 char[] cbuf = new char[256]; 122 int nChars = 0; 123 124 while ((nChars = read.read(cbuf)) != -1) { 125 write.write(cbuf, 0, nChars); 126 } 127 128 commandOutput = write.getBuffer().toString(); 129 } else { 130 // log.log(Level.WARNING,"No bufferOutput..."); 131 proc.waitFor(); 132 } 133 //proc.waitFor(); 134 135 // TODO: This is a hack for a bug that showed up 136 // after RC2. I don't understand if it's a problem caused by a code 137 // change, I hardly see how, or upgrade of the compiler. 138 // The problem is that sometimes proc.exitValue() would generate 139 // an exception, even if before was executed proc.waitFor(). 140 // Seems some sort of problem of synchronization. 141 // Waiting for a second seems to make the problem disappear. 142 try { 143 Thread.sleep(1000); 144 } catch (Exception e) { 145 } 146 147 exitStatus = proc.exitValue(); 148 } catch (Exception e) { 149 log.error("Command line task failed", e); 150 exitStatus = -1; 151 } 152 } 153 154 public void destroy() { 155 try { 156 proc.destroy(); 157 log.warn("The thread command had to be destroyed"); 158 } catch (Exception e) { 159 log.fatal("The thread command could not be destroyed",e); 160 } 161 } 162 163 /** Returns all the output of the command. 164 * @return the output of the command line 165 */ 166 public String getOutput() { 167 return commandOutput; 168 } 169 170 /** Returns the output of the command 171 * @return the output of the command 172 */ 173 public BufferedReader getOutputReader() { 174 if (commandOutput == null) { 175 return null; 176 } 177 178 return new BufferedReader(new StringReader(commandOutput)); 179 } 180 181 /** 182 * @param args the command line arguments 183 */ 184 public static void main(String[] args) { 185 CommandLineTask test = new CommandLineTask(args[1], true); 186 System.out.println("Executing \"" + args[1] + "\": "); 187 test.execute(); 188 System.out.println(); 189 System.out.println("Output: " + test.getOutput()); 190 System.out.println(); 191 System.out.println("Exit status: " + test.getExitStatus()); 192 } 193 }