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

com.sun.enterprise.universal.process.ProcessManager Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2022, 2024 Contributors to the Eclipse Foundation
 * Copyright (c) 2009, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package com.sun.enterprise.universal.process;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;


/**
 * Use this class for painless process spawning.
 * 

* This class was originally written to be compatible with JDK 1.4, using Runtime.exec(), * but has been refactored to use ProcessBuilder for better control and configurability. * * @since JDK 1.4 * @author bnevins 2005 */ public class ProcessManager { private static final Logger LOG = System.getLogger(ProcessManager.class.getName()); protected final ProcessBuilder builder; private String stdout; private String stderr; private int timeout; private String textToWaitFor; private boolean echo = true; private String[] stdinLines; public ProcessManager(String... cmds) { builder = new ProcessBuilder(cmds); } public ProcessManager(List cmdline) { builder = new ProcessBuilder(cmdline); } public void setTimeoutMsec(int num) { if (num > 0) { timeout = num; } } public void setEnvironment(String name, String value) { Map env = builder.environment(); env.put(name, value); } public void setWorkingDir(File directory) { builder.directory(directory); } public void setStdinLines(List list) { if (list != null && !list.isEmpty()) { stdinLines = list.toArray(String[]::new); } } /** * Should the output of the process be echoed to stdout? * * @param newEcho */ public void setEcho(boolean newEcho) { echo = newEcho; } /** * If not null, should wait until this text is found in standard output instead of waiting until the process terminates * * @param textToWaitFor */ public void setTextToWaitFor(String textToWaitFor) { this.textToWaitFor = textToWaitFor; } public int execute() throws ProcessManagerException { LOG.log(Level.DEBUG, "Executing command:\n command={0} \nenv={1}", builder.command(), builder.environment()); final Process process; try { process = builder.start(); } catch (IOException e) { throw new IllegalStateException("Could not execute command: " + builder.command(), e); } ReaderThread threadErr = new ReaderThread(process.getErrorStream(), echo, "stderr", Thread.currentThread(), textToWaitFor); threadErr.start(); ReaderThread threadOut = new ReaderThread(process.getInputStream(), echo, "stdout", Thread.currentThread(), textToWaitFor); threadOut.start(); try { try { writeStdin(process); final int result = await(process); if (textToWaitFor != null) { threadErr.finish(1000L); threadOut.finish(1000L); if( !threadOut.isTextFound() && !threadErr.isTextFound()) { throw new ProcessManagerException("Process finished but text " + textToWaitFor + " not found in output"); } } return result; } catch (InterruptedException e) { if (threadOut.isTextFound() || threadErr.isTextFound()) { return 0; } else { throw e; } } finally { stderr = threadErr.finish(1000L); stdout = threadOut.finish(1000L); } } catch (ProcessManagerException pme) { throw pme; } catch (Exception e) { throw new ProcessManagerException(e); } finally { if (process.isAlive() && textToWaitFor == null) { destroy(process); } } } private void destroy(Process process) { process.destroy(); // Wait for a while to let the process stop try { boolean exited = process.waitFor(10, TimeUnit.SECONDS); if (!exited) { // If the process hasn't exited, force it to stop process.destroyForcibly(); } } catch (InterruptedException e) { LOG.log(Level.INFO, "Interrupted while waiting for process to terminate", e); Thread.currentThread().interrupt(); } } public String getStdout() { return stdout; } public String getStderr() { return stderr; } @Override public String toString() { return builder.command().toString(); } private void writeStdin(Process process) throws ProcessManagerException { if (stdinLines == null || stdinLines.length == 0) { return; } if (process == null) { throw new ProcessManagerException("Parameter process was null."); } try (PrintWriter pipe = new PrintWriter( new BufferedWriter(new OutputStreamWriter(process.getOutputStream(), Charset.defaultCharset())))) { for (String stdinLine : stdinLines) { LOG.log(Level.DEBUG, "InputLine --> {0} <--", stdinLine); pipe.println(stdinLine); pipe.flush(); } } catch (Exception e) { throw new ProcessManagerException(e); } } private int await(Process process) throws InterruptedException, ProcessManagerException { if (timeout > 0) { if (process.waitFor(timeout, TimeUnit.MILLISECONDS)) { return process.exitValue(); } throw new ProcessManagerTimeoutException("Process is still running, timeout " + timeout + " ms exceeded."); } return process.waitFor(); } static class ReaderThread extends Thread { private final BufferedReader reader; private final StringBuilder sb; private final boolean echo; private final AtomicBoolean stop = new AtomicBoolean(); private final Thread threadWaitingForProcess; private final String textToWaitFor; private volatile boolean textFound = false; ReaderThread(InputStream stream, boolean echo, String threadName) { this(stream, echo, threadName, null, null); } ReaderThread(InputStream stream, boolean echo, String threadName, Thread threadWaitingForProcess, String textToWaitFor) { setName(threadName); this.reader = new BufferedReader(new InputStreamReader(stream, Charset.defaultCharset())); this.sb = new StringBuilder(); this.echo = echo; this.threadWaitingForProcess = threadWaitingForProcess; this.textToWaitFor = textToWaitFor; } @Override public void run() { try { while (true) { String line; if (reader.ready()) { line = reader.readLine(); } else if (stop.getAcquire()) { break; } else { Thread.yield(); continue; } interruptWaitingThreadIfTextFound(line); sb.append(line).append('\n'); if (echo) { System.out.println(line); } } } catch (Exception e) { LOG.log(Level.ERROR, "ReaderThread broke ...", e); } finally { try { reader.close(); } catch (IOException e) { LOG.log(Level.ERROR, "Failed to close BufferedReader", e); } } LOG.log(Level.TRACE, "ReaderThread exiting..."); } /** * Asks the thread to finish it's job and waits until the thread dies. *

* @param timeout The maximal time for the waiting. * * @return the final output of the process. */ public String finish(long timeout) { stop.setRelease(true); try { join(timeout); } catch (InterruptedException ex) { // nothing to do } return sb.toString(); } private void interruptWaitingThreadIfTextFound(String line) { if (threadWaitingForProcess != null && textToWaitFor != null && line.contains(textToWaitFor)) { textFound = true; threadWaitingForProcess.interrupt(); } } public boolean isTextFound() { return textFound; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy