1 /*** 2 * Cecilia ADL Compiler 3 * Copyright (C) 2006-2008 STMicroelectronics 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * 19 * Contact: fractal@objectweb.org 20 * 21 * Author:Matthieu Leclercq 22 */ 23 24 package org.objectweb.fractal.cecilia.adl.compiler; 25 26 import java.io.BufferedReader; 27 import java.io.IOException; 28 import java.io.InputStreamReader; 29 import java.util.Arrays; 30 import java.util.List; 31 import java.util.logging.Level; 32 import java.util.logging.Logger; 33 34 import org.objectweb.fractal.adl.ADLException; 35 import org.objectweb.fractal.adl.CompilerError; 36 import org.objectweb.fractal.adl.error.GenericErrors; 37 import org.objectweb.fractal.adl.util.FractalADLLogManager; 38 import org.objectweb.fractal.cecilia.adl.directives.DirectiveHelper; 39 40 /** 41 * This helper class provides method to execute external commands. 42 */ 43 public final class ExecutionHelper { 44 private ExecutionHelper() { 45 } 46 47 // The io logger 48 protected static Logger logger = FractalADLLogManager.getLogger("io"); 49 50 /** 51 * Executes the given command line and returns the exit value. The given 52 * command is splited on space character boundary (this method is equivalent 53 * to <code>exec(execTitle, command.split("\\s"))</code>)<br> 54 * Note that the {@link #exec(String, List<String>)} method is safer since it 55 * while not split command line on space character boundary which may produce 56 * unexpected result if arguments may contains spaces. 57 * 58 * @param command the command to execute. 59 * @return the exit value 60 * @throws ADLException If an error occurs while running the command. 61 * @throws InterruptedException if the calling thread has been interrupted 62 * while waiting for the process to finish. 63 * @see #exec(String, List<String>) 64 */ 65 public static int exec(final String command) throws ADLException, 66 InterruptedException { 67 return exec(null, command); 68 } 69 70 /** 71 * Executes the given command line and returns the exit value. The given 72 * command is splited on space character boundary, unless the space is 73 * escaped by a backslash.<br> 74 * Note that the {@link #exec(String, List<String>)} method is safer since it 75 * while not split command line on space character boundary which may produce 76 * unexpected result if arguments may contains spaces. 77 * 78 * @param execTitle the message to be logged as a header of the execution. May 79 * be <code>null</code>. 80 * @param command the command to execute. 81 * @return the exit value 82 * @throws ADLException If an error occurs while running the command. 83 * @throws InterruptedException if the calling thread has been interrupted 84 * while waiting for the process to finish. 85 * @see #exec(String, List<String>) 86 */ 87 public static int exec(final String execTitle, final String command) 88 throws ADLException, InterruptedException { 89 return exec(execTitle, DirectiveHelper.splitOptionString(command)); 90 } 91 92 /** 93 * Executes the given command line and returns the exit value.<br> 94 * This method will issue some messages on the <code>io</code> logger. If 95 * the {@link Level#FINE FINE} level is enabled, the full command line will be 96 * logged. If the {@link Level#INFO INFO} level is enabled, the given 97 * <code>execTitle</code> will be logged. Finally, if the process produces 98 * output on its standard error stream. This output will be logged with the 99 * {@link Level#SEVERE SEVERE} level preceded by the <code>execTitle</code> 100 * if it has not been logged yet. 101 * 102 * @param execTitle the message to be logged as a header of the execution. May 103 * be <code>null</code>. 104 * @param cmdList the command to execute. 105 * @return the exit value 106 * @throws ADLException If an error occurs while running the command. 107 * @throws InterruptedException if the calling thread has been interrupted 108 * while waiting for the process to finish. 109 */ 110 public static int exec(final String execTitle, final List<String> cmdList) 111 throws ADLException, InterruptedException { 112 final Process process; 113 try { 114 process = new ProcessBuilder(cmdList).redirectErrorStream(true).start(); 115 } catch (final IOException e1) { 116 throw new ADLException(CompilerErrors.EXECUTION_ERROR, cmdList.get(0)); 117 } 118 final boolean titleLogged; 119 120 if (logger.isLoggable(Level.INFO) && execTitle != null) { 121 logger.info(execTitle); 122 titleLogged = true; 123 } else { 124 titleLogged = false; 125 } 126 127 if (logger.isLoggable(Level.FINE)) { 128 String command = ""; 129 for (final String cmd : cmdList) { 130 command += cmd + " "; 131 } 132 logger.fine(command); 133 } 134 135 // Read output produced by process in a parallele thread in order to avoid 136 // the process to block 137 final Thread readerThread = new Thread() { 138 @Override 139 public void run() { 140 // output output and error stream on the logger. 141 final BufferedReader reader = new BufferedReader(new InputStreamReader( 142 process.getInputStream())); 143 try { 144 String line = reader.readLine(); 145 if (line != null) { 146 // if the title has not been printed yet. 147 if (!titleLogged) { 148 String command = ""; 149 for (final String cmd : cmdList) { 150 command += cmd + " "; 151 } 152 logger.severe((execTitle == null) ? command : execTitle); 153 } 154 do { 155 logger.severe(line); 156 line = reader.readLine(); 157 } while (line != null); 158 } 159 reader.close(); 160 } catch (final IOException e) { 161 throw new CompilerError(GenericErrors.INTERNAL_ERROR, e, 162 "Can't read error stream of process"); 163 } 164 } 165 }; 166 167 readerThread.start(); 168 final int rValue = process.waitFor(); 169 readerThread.join(); 170 171 return rValue; 172 } 173 174 /** 175 * Executes the given command line and returns the exit value. 176 * 177 * @param execTitle the message to be logged as a header of the execution. May 178 * be <code>null</code>. 179 * @param cmdArray the command to execute. 180 * @return the exit value 181 * @throws ADLException If an error occurs while running the command. 182 * @throws InterruptedException if the calling thread has been interrupted 183 * while waiting for the process to finish. 184 * @see #exec(String, List<String>) 185 * @see Runtime#exec(String[]) 186 */ 187 public static int exec(final String execTitle, final String[] cmdArray) 188 throws ADLException, InterruptedException { 189 return exec(execTitle, Arrays.asList(cmdArray)); 190 } 191 }