/**
* Copyright (C) 2008-2010, Squale Project - http://www.squale.org
*
* This file is part of Squale.
*
* Squale is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or any later version.
*
* Squale is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Squale. If not, see <http://www.gnu.org/licenses/>.
*/
package org.squale.squalix.util.process;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.StringTokenizer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.squale.squalix.messages.Messages;
/**
* Manager de lancement de processus externe Une processus permet le lancement d'une commande externe et son suivi en
* terme de flux de sortie sur stdout et stderr
*/
public class ProcessManager
{
/**
* Logger.
*/
private static final Log LOGGER = LogFactory.getLog( ProcessManager.class );
/** R�pertoire d'ex�cution */
private File mDir;
/** Environnement d'ex�cution */
private String[] mEnvp;
/** Commande � ex�cuter */
private String[] mCommand;
/** Handler de sortie */
private ProcessOutputHandler mOutputHandler;
/** le fichier de log */
private File mLog;
/**
* Constructeur
*
* @param pCommand commande � lancer
* @param pEnvp environnement d'ex�cution
* @param pDir r�pertoire d'ex�cution
*/
public ProcessManager( String[] pCommand, String pEnvp[], File pDir )
{
this( pCommand, pEnvp, pDir, null );
}
/**
* Constructeur
*
* @param pCommand commande � lancer
* @param pEnvp environnement d'ex�cution
* @param pDir r�pertoire d'ex�cution
* @param pLog le fichier de log
*/
public ProcessManager( String[] pCommand, String pEnvp[], File pDir, File pLog )
{
mCommand = pCommand;
mEnvp = pEnvp;
mDir = pDir;
mLog = pLog;
}
/**
* Constructeur
*
* @param pCommand commande � lancer
* @param pEnvp environnement d'ex�cution
* @param pDir r�pertoire d'ex�cution
*/
public ProcessManager( String pCommand, String pEnvp[], File pDir )
{
this( pCommand, pEnvp, pDir, null );
}
/**
* Constructeur
*
* @param pCommand commande � lancer
* @param pEnvp environnement d'ex�cution
* @param pDir r�pertoire d'ex�cution
* @param pLog le fichier de log
*/
public ProcessManager( String pCommand, String pEnvp[], File pDir, File pLog )
{
mCommand = splitCommand( pCommand );
mEnvp = pEnvp;
mDir = pDir;
mLog = pLog;
}
/**
* affectation du handler d'output
*
* @param pOutputHandler handler de sortie
*/
public void setOutputHandler( ProcessOutputHandler pOutputHandler )
{
mOutputHandler = pOutputHandler;
}
/**
* Lancement du processus externe
*
* @param pHandler interface de traitement des erreurs
* @return code de retour d'ex�cution
* @throws IOException si erreur
* @throws InterruptedException si erreur
*/
public int startProcess( ProcessErrorHandler pHandler )
throws IOException, InterruptedException
{
int result;
Runtime runtime = Runtime.getRuntime();
// Informations de debug
if ( LOGGER.isDebugEnabled() )
{
LOGGER.debug( Messages.getString( "process.dir" ) + mDir );
for ( int i = 0; i < mCommand.length; i++ )
{
LOGGER.debug( Messages.getString( "process.argument" ) + i + " " + mCommand[i] );
}
}
// V�rification de l'existence du r�pertoire de lancement
// cel� peut �tre � l'origine de situations de blocage
if ( ( mDir != null ) && ( !mDir.exists() || !mDir.isDirectory() ) )
{
throw new IOException( "unexisting directory: " + mDir );
}
Process processCheck = runtime.exec( mCommand, mEnvp, mDir );
/*
* Pour �viter le lock du process, il faut envoyer le flux d'erreur et le flux de sortie sur des threads.
*/
ProcessErrorStream err = new ProcessErrorStream( processCheck.getErrorStream(), pHandler );
Thread errorThread = new Thread( err, "StderrStreamConsumer" );
errorThread.start();
ProcessOutputStream outp = createOutputStream( processCheck.getInputStream(), mOutputHandler );
Thread outputThread = new Thread( outp, "StdoutStreamConsumer" );
outputThread.start();
/* Obtention du code de retour du process */
result = processCheck.waitFor();
// Attente de la terminaison des threads
// pour etre certain de recuperer les donn�es
// Voir bugid 4422496 de Sun
outputThread.join();
errorThread.join();
return result;
}
/**
* @param pInput l'entr�e
* @param pHandler le handler de sortie
* @return le process de sortie � utiliser
* @throws IOException si erreur
*/
public ProcessOutputStream createOutputStream( InputStream pInput, ProcessOutputHandler pHandler )
throws IOException
{
ProcessOutputStream process = null;
if ( null == mLog )
{
process = new ProcessOutputStream( pInput, mOutputHandler );
}
else
{
// Si le fichier contient d�j� des traces, on ne les �crase pas (le true du FileWriter)
process =
new ProcessOutputStreamInFile( pInput, mOutputHandler,
new BufferedWriter( new FileWriter( mLog, true ) ) );
}
return process;
}
/**
* D�coupage de la commande en plusieurs param�tres
*
* @param pCommand ligne de commande
* @return la commande splitt�e
*/
private String[] splitCommand( String pCommand )
{
int count = 0;
String cmdarray[];
StringTokenizer st;
if ( pCommand.length() == 0 )
{
throw new IllegalArgumentException( "Empty command" );
}
st = new StringTokenizer( pCommand );
count = st.countTokens();
cmdarray = new String[count];
st = new StringTokenizer( pCommand );
count = 0;
while ( st.hasMoreTokens() )
{
cmdarray[count++] = st.nextToken();
}
return cmdarray;
}
/**
* @return l'outputHandler
*/
public ProcessOutputHandler getOutputHandler()
{
return mOutputHandler;
}
}