001 /* 002 * $RCSfile: CSHCommandLineTask.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 gov.bnl.star.offline.scheduler.ComponentLibrary; 026 import java.io.*; 027 import java.util.logging.Level; 028 import org.apache.log4j.Logger; 029 030 031 032 /** A command line task. 033 * 034 * @author Gabriele Carcassi 035 * @version $Revision: 1.13 $ $Date: 2006/11/21 00:41:29 $ 036 */ 037 public class CSHCommandLineTask extends Task { 038 static private Logger log = Logger.getLogger(CSHCommandLineTask.class.getName()); 039 //ISSUE: Unixism 040 private static String csh = ComponentLibrary.getInstance().getProgramLocation("csh"); 041 private String commandLine; 042 private String[] commandLineArray; 043 private boolean bufferOutput; 044 private boolean bufferError; 045 private String commandOutput; 046 private Process proc; 047 048 /** A new command line task. 049 * <p> 050 * WARNING: the parsing of the command line won't be what you would have while 051 * executing at a UNIX prompt. The command line won't be passed to the shell, 052 * that is why it may have different result. For example, wildcards are usually 053 * resolved by the shell, and not by the program themselves. 054 * @param commandLine the command line to be executed 055 */ 056 public CSHCommandLineTask(String commandLine) { 057 this(commandLine, false); 058 } 059 060 /** A new command line task. This allows you to buffer the output of the command. 061 * You can retrieve the ouput with <CODE>getOutput</CODE> or 062 * <CODE>getOutputReader</CODE> 063 * <p> 064 * WARNING: the parsing of the command line won't be what you would have while 065 * executing at a UNIX prompt. The command line won't be passed to the shell, 066 * that is why it may have different result. For example, wildcards are usually 067 * resolved by the shell, and not by the program themselves. 068 * @param commandLine the command line to be executed 069 * @param bufferCommandOutput if true, the output will be buffered 070 */ 071 public CSHCommandLineTask(String commandLine, boolean bufferCommandOutput) { 072 this.commandLine = commandLine; 073 this.bufferOutput = bufferCommandOutput; 074 } 075 076 /** A new command line task with a timeout. The command will be aborted if the 077 * process doesn't return before the timeout. 078 * <p> 079 * WARNING: the parsing of the command line won't be what you would have while 080 * executing at a UNIX prompt. The command line won't be passed to the shell, 081 * that is why it may have different result. For example, wildcards are usually 082 * resolved by the shell, and not by the program themselves. 083 * @param commandLine 084 * @param msTimeout 085 */ 086 public CSHCommandLineTask(String commandLine, int msTimeout) { 087 super(msTimeout); 088 this.commandLine = commandLine; 089 } 090 091 public CSHCommandLineTask(String commandLine, int msTimeout, boolean bufferCommandOutput) { 092 super(msTimeout); 093 this.commandLine = commandLine; 094 this.bufferOutput = bufferCommandOutput; 095 } 096 097 public CSHCommandLineTask(String commandLine, boolean bufferCommandError, int msTimeout) { 098 super(msTimeout); 099 this.commandLine = commandLine; 100 this.bufferOutput = bufferCommandError; 101 this.bufferError = bufferCommandError; 102 } 103 104 /** Calls the external command. Don't use this directly, or your task won't be 105 * executed in a separate thread. Use <CODE>execute</CODE> instead. 106 */ 107 public void run() { 108 try { 109 // Beware of Unixism ... 110 if (System.getProperty("os.name").startsWith("Win")){ 111 proc = Runtime.getRuntime().exec(commandLine); 112 } else { 113 proc = Runtime.getRuntime().exec( 114 new String[] {csh, "-cf", commandLine} 115 ); // Explicit shell needs to be specified 116 // otherwise, LSF breaks probably because 117 // of the LSB shell env. 118 } 119 120 // will use a StrigWriter 121 StringWriter write = new StringWriter(); 122 char[] cbuf = new char[256]; 123 int nChars = 0; 124 125 if (bufferOutput) { 126 InputStreamReader read = new InputStreamReader(proc.getInputStream()); 127 while ( (nChars = read.read(cbuf)) != -1 ){ 128 write.write(cbuf,0,nChars); 129 } 130 read.close(); 131 } 132 if (bufferError) { 133 InputStreamReader errorStream = new InputStreamReader(proc.getErrorStream()); 134 while ( (nChars = errorStream.read(cbuf)) != -1) { 135 write.write(cbuf, 0, nChars); 136 } 137 errorStream.close(); 138 } 139 140 commandOutput = write.getBuffer().toString(); 141 log.info(" We got return string=" + commandOutput.trim()); 142 143 // This Thread is mainly composed of a Runtime.getRuntime().exec() 144 // This has to be waited for. 145 try { 146 proc.waitFor(); 147 } catch (InterruptedException e){ 148 log.warn("[proc] was interrupted ",e); 149 } 150 151 // TODO: This is a hack for a bug that showed up 152 // after RC2. I don't understand if it's a problem caused by a code 153 // change, I hardly see how, or upgrade of the compiler. 154 // The problem is that sometimes proc.exitValue() would generate 155 // an exception, even if before was executed proc.waitFor(). 156 // Seems some sort of problem of synchronization. 157 // Waiting for a second seems to make the problem disappear. 158 //try { 159 // Thread.sleep(1000); 160 //} catch (Exception e) { 161 //} 162 exitStatus = proc.exitValue(); 163 164 } catch (Exception e) { 165 log.warn("Command line task failed", e); 166 exitStatus = -1; 167 } 168 } 169 170 public void destroy() { 171 try { 172 proc.destroy(); 173 log.warn("The thread process had to be destroyed"); 174 } catch (Exception e) { 175 log.fatal("The thread process could not be destroyed",e); 176 } 177 } 178 179 /** Returns all the output of the command. 180 * @return the output of the command line 181 */ 182 public String getOutput() { 183 return commandOutput; 184 } 185 186 /** Returns the output of the command 187 * @return the output of the command 188 */ 189 public BufferedReader getOutputReader() { 190 if (commandOutput == null) { 191 return null; 192 } 193 194 return new BufferedReader(new StringReader(commandOutput)); 195 } 196 197 /** 198 * @param args the command line arguments 199 */ 200 public static void main(String[] args) { 201 CommandLineTask test = new CommandLineTask(args[1], true); 202 System.out.println("Executing \"" + args[1] + "\": "); 203 test.execute(); 204 System.out.println(); 205 System.out.println("Output: " + test.getOutput()); 206 System.out.println(); 207 System.out.println("Exit status: " + test.getExitStatus()); 208 } 209 210 211 } 212 213 214