Java tutorial
/* * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2004, 2005, 2006], Hyperic, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. This program 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 General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ /* * The Apache Software License, Version 1.1 * * Copyright (c) 2000 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Ant", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.hyperic.util.exec; import java.io.File; import java.io.IOException; import java.io.BufferedReader; import java.io.StringReader; import java.io.ByteArrayOutputStream; import java.util.*; /* 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. Costin */ /** * Runs an external program. * * @author thomas.haas@softwired-inc.com */ public class Execute { /** Invalid exit code. **/ public final static int INVALID = Integer.MAX_VALUE; private String[] cmdl = null; private String[] env = null; private int exitValue = INVALID; private ExecuteStreamHandler streamHandler; private ExecuteWatchdog watchdog; private File workingDirectory = null; private boolean newEnvironment = false; private static Vector procEnvironment = null; /** * Find the list of environment variables for this process. */ 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 osname = System.getProperty("os.name").toLowerCase(Locale.US); 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 <code>PumpStreamHandler</code> 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 <code>null</code> 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 commandline array of Strings, each element of which has * an environment variable settings in format <em>key=value</em> */ public void setEnvironment(String[] env) { this.env = env; } /** * Sets the working directory of the process to execute. * * <p>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; } // costin boolean wait = true; public void setWait(boolean b) { wait = b; } Process process; /** * Runs a process defined by the command line and returns its exit status. * * @return the exit status of the subprocess or <code>INVALID</code> * @exception java.io.IOExcpetion The exception is thrown, 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); 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; } 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 "); } } 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() { 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 (((String) 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.nextElement()); } 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 */ 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) { // ex.printStackTrace(); System.err.println("An error has occurred in Execute."); return -1; } } private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(Execute.class); }