All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.util.exec.Execute Maven / Gradle / Ivy

/*
 * Copyright 2002-2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

package org.springframework.util.exec;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.StringTokenizer;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Runs an external program. Derived from ant exec task. All the 'backward compat with jdk1.1, 1.2' removed. Since
 * jdk1.3 supports working dir, no need for scripts. All ant-specific code has been removed as well, this is a
 * completely independent component.
 *
 *
 * @author [email protected]
 * @author Costin Leau
 */
public class Execute {

	private static Log log = LogFactory.getLog(Execute.class);

	/** Invalid exit code. **/
	public static final int INVALID = Integer.MAX_VALUE;

	private String[] cmdl = null;
	private String[] env = null;
	private int exitValue = INVALID;
	private final ExecuteStreamHandler streamHandler;
	private final ExecuteWatchdog watchdog;
	private File workingDirectory = null;
	private boolean newEnvironment = false;
	private Process process;

	private static Vector procEnvironment = null;

	/**
	 * Find the list of environment variables for this process.
	 *
	 * @return The environment.
	 */
	public static synchronized Vector getProcEnvironment() {

		if (procEnvironment != null) {
			return procEnvironment;
		}

		procEnvironment = new Vector();
		try {
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			Execute exe = new Execute(new PumpStreamHandler(out));
			exe.setCommandline(getProcEnvCommand());
			// Make sure we do not recurse forever
			exe.setNewenvironment(true);
			int retval = exe.execute();
			if (retval != 0) {
				// Just try to use what we got
			}

			BufferedReader in = new BufferedReader(new StringReader(out.toString()));
			String var = null;
			String line, lineSep = System.getProperty("line.separator");
			while ((line = in.readLine()) != null) {
				if (line.indexOf('=') == -1) {
					// Chunk part of previous env var (UNIX env vars can
					// contain embedded new lines).
					if (var == null) {
						var = lineSep + line;
					} else {
						var += lineSep + line;
					}
				} else {
					// New env var...append the previous one if we have it.
					if (var != null) {
						procEnvironment.addElement(var);
					}
					var = line;
				}
			}
			// Since we "look ahead" before adding, there's one last env var.
			procEnvironment.addElement(var);
		} catch (Exception exc) {
			exc.printStackTrace();
			// Just try to see how much we got
		}
		return procEnvironment;
	}

	private static String[] getProcEnvCommand() {
		if (Os.isFamily("os/2")) {
			// OS/2 - use same mechanism as Windows 2000
			// Not sure
			String[] cmd = { "cmd", "/c", "set" };
			return cmd;
		} else if (Os.isFamily("windows")) {
			String[] cmd = { "cmd", "/c", "set" };
			return cmd;
		} else if (Os.isFamily("unix")) {
			// Generic UNIX
			// Alternatively one could use: /bin/sh -c env
			String[] cmd = { "/usr/bin/env" };
			return cmd;
		} else if (Os.isFamily("netware")) {
			String[] cmd = { "env" };
			return cmd;
		} else {
			// MAC OS 9 and previous
			// TODO: I have no idea how to get it, someone must fix it
			String[] cmd = null;
			return cmd;
		}
	}

	/**
	 * Creates a new execute object using PumpStreamHandler for stream handling.
	 */
	public Execute() {
		this(new PumpStreamHandler(), null);
	}

	/**
	 * Creates a new execute object.
	 *
	 * @param streamHandler the stream handler used to handle the input and output streams of the subprocess.
	 */
	public Execute(ExecuteStreamHandler streamHandler) {
		this(streamHandler, null);
	}

	/**
	 * Creates a new execute object.
	 *
	 * @param streamHandler the stream handler used to handle the input and output streams of the subprocess.
	 * @param watchdog a watchdog for the subprocess or null to to disable a timeout for the subprocess.
	 */
	public Execute(ExecuteStreamHandler streamHandler, ExecuteWatchdog watchdog) {
		this.streamHandler = streamHandler;
		this.watchdog = watchdog;
	}

	/**
	 * Returns the commandline used to create a subprocess.
	 *
	 * @return the commandline used to create a subprocess
	 */
	public String[] getCommandline() {
		return cmdl;
	}

	public String getCommandLineString() {
		return array2string(getCommandline());
	}

	/**
	 * Sets the commandline of the subprocess to launch.
	 *
	 * @param commandline the commandline of the subprocess to launch
	 */
	public void setCommandline(String[] commandline) {
		cmdl = commandline;
	}

	/**
	 * Set whether to propagate the default environment or not.
	 *
	 * @param newenv whether to propagate the process environment.
	 */
	public void setNewenvironment(boolean newenv) {
		newEnvironment = newenv;
	}

	/**
	 * Returns the environment used to create a subprocess.
	 *
	 * @return the environment used to create a subprocess
	 */
	public String[] getEnvironment() {
		if (env == null || newEnvironment) {
			return env;
		}
		return patchEnvironment();
	}

	/**
	 * Sets the environment variables for the subprocess to launch.
	 *
	 * @param env array of Strings, each element of which has an environment variable settings in format
	 * key=value
	 */
	public void setEnvironment(String[] env) {
		this.env = env;
	}

	/**
	 * Sets the working directory of the process to execute.
	 *
	 * 

This is emulated using the antRun scripts unless the OS is Windows NT in which case a cmd.exe is spawned, or * MRJ and setting user.dir works, or JDK 1.3 and there is official support in java.lang.Runtime. * * @param wd the working directory of the process. */ public void setWorkingDirectory(File wd) { workingDirectory = wd; } /** * Runs a process defined by the command line and returns its exit status. * * @return the exit status of the subprocess or INVALID * @throws Exception if launching of the subprocess failed */ public int execute() throws Exception { process = Runtime.getRuntime().exec(getCommandline(), getEnvironment(), workingDirectory); try { streamHandler.setProcessInputStream(process.getOutputStream()); streamHandler.setProcessOutputStream(process.getInputStream()); streamHandler.setProcessErrorStream(process.getErrorStream()); } catch (IOException e) { process.destroy(); throw e; } streamHandler.start(); if (watchdog != null) { watchdog.start(process, Thread.currentThread()); } if (log.isTraceEnabled()) { log.trace("Waiting process "); } waitFor(process); process = null; if (log.isTraceEnabled()) { log.trace("End waiting, stop threads "); } if (watchdog != null) { watchdog.stop(); } if (log.isTraceEnabled()) { log.trace("Watchdog stopped "); } streamHandler.stop(); if (log.isTraceEnabled()) { log.trace("Stream handler stopped "); } if (watchdog != null) { Exception ex = watchdog.getException(); if (ex != null) { throw ex; } } int exit = getExitValue(); if (log.isDebugEnabled()) { log.debug("Done exit=" + exit + " " + getCommandLineString()); } return exit; } public void kill() { if (process != null) { process.destroy(); } } private String array2string(String sa[]) { if (sa == null) { return "null"; } StringBuffer sb = new StringBuffer(); for (int i = 0; i < sa.length; i++) { sb.append(sa[i]).append(" "); } return sb.toString(); } protected void waitFor(Process process) { try { process.waitFor(); setExitValue(process.exitValue()); } catch (InterruptedException e) { log.info("waitFor() interrupted "); Thread.currentThread().interrupt(); } } protected void setExitValue(int value) { exitValue = value; } /** * query the exit value of the process. * * @return the exit value, 1 if the process was killed, or Project.INVALID if no exit value has been received */ public int getExitValue() { return exitValue; } /** * Patch the current environment with the new values from the user. * * @return the patched environment */ private String[] patchEnvironment() { @SuppressWarnings("unchecked") Vector osEnv = (Vector) getProcEnvironment().clone(); for (int i = 0; i < env.length; i++) { int pos = env[i].indexOf('='); // Get key including "=" String key = env[i].substring(0, pos + 1); int size = osEnv.size(); for (int j = 0; j < size; j++) { if ((osEnv.elementAt(j)).startsWith(key)) { osEnv.removeElementAt(j); break; } } osEnv.addElement(env[i]); } String[] result = new String[osEnv.size()]; osEnv.copyInto(result); return result; } public static int execute(Vector envVars, String cmd, File baseDir) { Vector v = new Vector(); StringTokenizer st = new StringTokenizer(cmd, " "); while (st.hasMoreTokens()) { v.addElement(st.nextToken()); } return execute(envVars, v, baseDir); } public static int execute(Vector envVars, Vector cmd, File baseDir) { return execute(envVars, cmd, baseDir, 10000 /* default time to wait */); } /** * Wrapper for common execution patterns * * @param envVars Environment variables to execute with (optional) * @param cmd a vector of the commands to execute * @param baseDir the base directory to run from (optional) * @param timeToWait milliseconds to wait for completion * * @return The result. */ public static int execute(Vector envVars, Vector cmd, File baseDir, int timeToWait) { try { // We can collect the out or provide in if needed ExecuteWatchdog watchdog = new ExecuteWatchdog(timeToWait); watchdog.setDontkill(true); PumpStreamHandler out = new PumpStreamHandler(); Execute exec = new Execute(out, watchdog); String cmdA[] = new String[cmd.size()]; cmd.toArray(cmdA); if (log.isDebugEnabled()) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < cmdA.length; i++) { sb.append(cmdA[i] + " "); } log.debug("Exec: " + sb.toString()); } exec.setCommandline(cmdA); if (envVars != null) { String env[] = new String[envVars.size()]; envVars.toArray(env); exec.setEnvironment(env); } exec.setNewenvironment(false); if (baseDir != null) { exec.setWorkingDirectory(baseDir); } exec.execute(); int status = exec.getExitValue(); log.debug("Exit value " + status); return status; } catch (Exception ex) { System.err.println("An error has occurred in Execute."); return -1; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy