/* * ProccessLauncher is a tool to launch an extern application * in a Java program with stream managed in separate threads. * * Copyright (C) 2006 Fabio MARAZZATO, Yann D'ISANTO * * This library 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 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package ext; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.jajuk.util.log.Log; /** * http://ydisanto.ftp-developpez.com/tutoriels/j2se/runtime/fichiers/ProcessLauncher.java * ProcessLauncher permet de lancer une application externe en consommant les * divers fluxs dans des threads separes. * * @author Fabio MARAZZATO * @author Yann D'ISANTO */ public class ProcessLauncher { private OutputStream out = null; private OutputStream err = null; private InputStream in = null; private Process process; private long timeout = 0L; private boolean finished = false; /** * Instantiates a new process launcher. */ public ProcessLauncher() { this(null, null, null, 0L); } /** * The Constructor. * * @param out Outputstream vers lequel sera redirige la sortie standard de * l'application externe (null pour ne pas rediriger). * @param err Outputstream vers lequel sera redirige la sortie d'erreur de * l'application externe (null pour ne pas rediriger). */ public ProcessLauncher(OutputStream out, OutputStream err) { this(out, err, null, 0L); } /** * The Constructor. * * @param out Outputstream vers lequel sera redirige la sortie standard de * l'application externe (null pour ne pas rediriger). * @param err Outputstream vers lequel sera redirige la sortie d'erreur de * l'application externe (null pour ne pas rediriger). * @param in InputStream vers lequel sera redirige l'entree standard de * l'application externe (null pour ne pas rediriger). */ public ProcessLauncher(OutputStream out, OutputStream err, InputStream in) { this(out, err, in, 0L); } /** * The Constructor. * * @param out Outputstream vers lequel sera redirige la sortie standard de * l'application externe (null pour ne pas rediriger). * @param err Outputstream vers lequel sera redirige la sortie d'erreur de * l'application externe (null pour ne pas rediriger). * @param timeout temps en millisecondes avant de forcer l'arret de l'application * externe (0 pour ne jamais forcer l'arret). */ public ProcessLauncher(OutputStream out, OutputStream err, long timeout) { this(out, err, null, timeout); } /** * The Constructor. * * @param out Outputstream vers lequel sera redirige la sortie standard de * l'application externe (null pour ne pas rediriger). * @param err Outputstream vers lequel sera redirige la sortie d'erreur de * l'application externe (null pour ne pas rediriger). * @param in InputStream vers lequel sera redirige l'entree standard de * l'application externe (null pour ne pas rediriger). * @param timeout temps en millisecondes avant de forcer l'arret de l'application * externe (0 pour ne jamais forcer l'arret). */ public ProcessLauncher(OutputStream out, OutputStream err, InputStream in, long timeout) { this.out = out; this.err = err; this.in = in; this.timeout = timeout < 0 ? 0L : timeout; } /** * Execute une ligne de commande dans un processus separe. * * @param command ligne de commande a executer * * @return valeur de retour du processus * * @throws IOException Signals that an I/O exception has occurred. */ final public int exec(String command) throws IOException { process = Runtime.getRuntime().exec(command); return execute(); } /** * Execute une commande avec ses parametres dans un processus separe. * * @param cmdarray tableau de String contenant la commande et ses parametres * * @return valeur de retour du processus * * @throws IOException Signals that an I/O exception has occurred. */ final public int exec(String[] cmdarray) throws IOException { process = Runtime.getRuntime().exec(cmdarray); return execute(); } /** * Execute une commande avec ses parametres dans un processus separe en * specifiant des variables d'environnement. * * @param cmdarray tableau de String contenant la commande et ses parametres * @param envp variables d'environnement * * @return valeur de retour du processus * * @throws IOException Signals that an I/O exception has occurred. */ final public int exec(String[] cmdarray, String[] envp) throws IOException { process = Runtime.getRuntime().exec(cmdarray, envp); return execute(); } /** * Execute une commande avec ses parametres dans un processus separe en * specifiant des variables d'environnement et le repertoire de travail. * * @param cmdarray tableau de String contenant la commande et ses parametres * @param envp variables d'environnement * @param dir repertoire de travail * * @return valeur de retour du processus * * @throws IOException Signals that an I/O exception has occurred. */ final public int exec(String[] cmdarray, String[] envp, File dir) throws IOException { process = Runtime.getRuntime().exec(cmdarray, envp, dir); return execute(); } /** * Execute une ligne de commande dans un processus separe en specifiant des * variables d'environnement. * * @param command ligne de commande * @param envp variables d'environnement * * @return valeur de retour du processus * * @throws IOException Signals that an I/O exception has occurred. */ final public int exec(String command, String[] envp) throws IOException { process = Runtime.getRuntime().exec(command, envp); return execute(); } /** * Execute une ligne de commande dans un processus separe en specifiant des * variables d'environnement et le repertoire de travail. * * @param command ligne de commande * @param envp variables d'environnement * @param dir repertoire de travail * * @return valeur de retour du processus * * @throws IOException Signals that an I/O exception has occurred. */ final public int exec(String command, String[] envp, File dir) throws IOException { process = Runtime.getRuntime().exec(command, envp, dir); return execute(); } /** * Execute. * * * @return the int */ private int execute() { int status = -1; // Consommation des fluxs de sortie standard et d'erreur dans des // threads separes. if (err == null) { try { process.getErrorStream().close(); } catch (IOException e) { Log.error(e); } } else { createStreamThread(process.getErrorStream(), err); } if (out == null) { try { process.getInputStream().close(); } catch (IOException e) { Log.error(e); } } else { createStreamThread(process.getInputStream(), out); } // Mapping de l'entree standard de l'application si besoin est. if (in != null) { createStreamThread(in, process.getOutputStream()); } if (timeout > 0L) { Thread processThread = createProcessThread(process); processThread.start(); try { processThread.join(timeout); try { status = process.exitValue(); } catch (IllegalThreadStateException itse) { process.destroy(); status = process.exitValue(); } } catch (InterruptedException ie) { Log.error(ie); } } else if (timeout == 0L) { try { status = process.waitFor(); } catch (InterruptedException ie) { Log.error(ie); } } finished = true; return status; } /** * Creates the stream thread. * * * @param is * @param os */ private void createStreamThread(final InputStream is, final OutputStream os) { new Thread(new Runnable() { @Override public void run() { BufferedInputStream bis = new BufferedInputStream(is); BufferedOutputStream bos = null; if (os != null) { bos = new BufferedOutputStream(os); } byte[] data = new byte[2048]; int nbRead = 0; try { while ((nbRead = bis.read(data)) > 0) { if (bos != null) { if (finished) { break; } bos.write(data, 0, nbRead); bos.flush(); } } } catch (IOException ioe) { Log.error(ioe); } } }, "Create Stream Thread").start(); } /** * Creates the process thread. * * * @param process * * @return the thread */ private Thread createProcessThread(final Process process) { return new Thread("Process Watcher Thread") { @Override public void run() { try { process.waitFor(); } catch (InterruptedException ie) { Log.error(ie); } } }; } /** * Renvoie l'OutputStream vers lequel a ete redirige le flux d'erreur de * l'application externe. * * @return l'OutputStream vers lequel a ete redirige le flux d'erreur de * l'application externe */ public OutputStream getErrorStream() { return err; } /** * Renvoie l'InputStream duquel les donnees sont envoyees au flux d'entree * standard de l'application externe. * * @return l'InputStream duquel les donnees sont envoyees au flux d'entree * standard de l'application externe */ public InputStream getInputStream() { return in; } /** * Renvoie l'OutputStream vers lequel a ete redirige le flux de sortie * standard de l'application externe. * * @return l'OutputStream vers lequel a ete redirige le flux de sortie * standard de l'application externe */ public OutputStream getOutputStream() { return out; } /** * Renvoie le timeout. * * @return le timeout */ public long getTimeout() { return timeout; } /** * Specifie l'Outputstream vers lequel sera redirige la sortie d'erreur de * l'application externe. * * @param err Outputstream vers lequel sera redirige la sortie d'erreur de * l'application externe (null pour ne pas rediriger) */ public void setErrorStream(OutputStream err) { this.err = err; } /** * Specifie l'InputStream vers lequel sera redirige l'entree standard de * l'application externe. * * @param in InputStream vers lequel sera redirige l'entree standard de * l'application externe (null pour ne pas rediriger) */ public void setInputStream(InputStream in) { this.in = in; } /** * Specifie l'Outputstream vers lequel sera redirige la sortie standard de * l'application externe. * * @param out Outputstream vers lequel sera redirige la sortie standard de * l'application externe (null pour ne pas rediriger) */ public void setOutputStream(OutputStream out) { this.out = out; } /** * Specifie le timeout temps en millisecondes avant de forcer l'arret de * l'application externe. * * @param timeout temps en millisecondes avant de forcer l'arret de l'application * externe (0 pour ne jamais forcer l'arret) */ public void setTimeout(long timeout) { this.timeout = timeout; } }