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();
}
};
}
}
