Shell.java package com.hy.toolsimport org.apache.commons.io.IOUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.io.*;import java.lang.reflect.Field;import java.util.concurrent.CountDownLatch;import java.util.concurren
package com.hy.tools import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.lang.reflect.Field; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; /** * author: houying * date : 17-6-30 * desc : */ public class Shell { private static final Logger logger = LoggerFactory.getLogger(Shell.class); private String cmd; private String dir; private String output; private Process process; private int processId; private int exitCode; private CountDownLatch completeLatch; private CountDownLatch startLatch; private OutputMonitorCallback callback; public Shell(String cmd, String dir, String output, OutputMonitorCallback callback) { this.cmd = cmd; this.dir = dir; this.output = output; this.callback = callback; this.exitCode = -1; this.completeLatch = new CountDownLatch(1); this.startLatch = new CountDownLatch(1); } public Shell(String cmd, String dir) { this(cmd, dir, null, null); } public void run(ExecutorService poolExecutor) { poolExecutor.execute(shellRunnable()); poolExecutor.execute(logRunnable()); } public void run() { new Thread(new Runnable() { @Override public void run() { logInternal(); } }).start(); executeInternal(); } public void kill() { if (process != null && processId != 0) { try { Runtime.getRuntime().exec(String.format("kill -15 %s", processId)); logger.info("kill -15 {}", processId); } catch (IOException e) { logger.error("Kill attempt failed.", e); e.printStackTrace(); } process.destroy(); } } public boolean awaitCompletion(long timeout) throws InterruptedException { return completeLatch.await(timeout, TimeUnit.MILLISECONDS); } public void awaitCompletion() throws InterruptedException { completeLatch.await(); } public int getExitCode() { return exitCode; } private int processId(final java.lang.Process process) { int processId = 0; try { Field f = process.getClass().getDeclaredField("pid"); f.setAccessible(true); processId = f.getInt(process); } catch (Throwable e) { e.printStackTrace(); } return processId; } private void executeInternal() { ProcessBuilder builder = new ProcessBuilder(cmd.split(" ")).redirectErrorStream(true) .directory(new File(dir)); try { process = builder.start(); processId = processId(process); logger.info("process {} start", processId); startLatch.countDown(); exitCode = process.waitFor(); logger.info("process {} end, exit code: {}", processId, exitCode); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { logger.warn("process was interrupted"); } finally { if (process != null) { IOUtils.closeQuietly(process.getInputStream()); IOUtils.closeQuietly(process.getOutputStream()); IOUtils.closeQuietly(process.getErrorStream()); } completeLatch.countDown(); logger.info("shell exit"); } } private void logInternal() { BufferedReader reader = null; try { startLatch.await(); reader = new BufferedReader(new InputStreamReader(process.getInputStream())); if (output != null) { writeLog(reader); } else { printLog(reader); } } catch (InterruptedException e) { logger.error("log thread interrupted"); } finally { IOUtils.closeQuietly(reader); logger.info("log thread exit"); } } private void printLog(BufferedReader reader) { String line; try { while( (line = reader.readLine()) != null) { logger.info("[shell log]: {}", line); if (callback != null) { if (!callback.callback(line, Shell.this)) { break; } } } } catch (IOException e) { logger.error("日志异常退出", e); } } private void writeLog(BufferedReader reader) { BufferedWriter writer = null; try { writer = new BufferedWriter(new FileWriter(output)); String line; while( (line = reader.readLine()) != null) { writer.write(line); writer.newLine(); if (callback != null) { if (!callback.callback(line, Shell.this)) { break; } } } } catch (IOException e) { logger.error("写日志异常退出", e.getMessage()); } finally { IOUtils.closeQuietly(writer); } } private Runnable shellRunnable() { return new Runnable() { public void run() { executeInternal(); } }; } private Runnable logRunnable() { return new Runnable() { public void run() { logInternal(); } }; } }