2021SC@SDUSC
上篇文章主要对模块openmeetins-util下src/main/mail文件下的三个类进行了分析,分别是ByteArrayDataSourse、IcalHandler、MailUtil类来实现创建数据源、对会议日历的处理、以及判断地址是否有效。接下来将继续分析util文件下的其他类。该篇文章将分析src/main下的process文件夹下的类。
目录
process
首先看process文件下有哪些类:
总共有三个类:分别是ProcessHelper、ProcessResult、ProcessResultList类,ProcessResult定义了一个实体类,ProcessHelper类获取并执行进程返回结果res,ProcessResultList类收集所有转换job的结果。
ProcessHelper类
//每个转换步骤创建的对象,每个调用的转换步骤和外部工具(如ImageMagick)都是一个//ConverterProcessMessage
public class ProcessResult {
public static final Integer ZERO = new Integer(0);
private String process;
private String command;
private String exception;
private String error;
private Integer exitCode;
private String out;
private boolean optional = false;
public ProcessResult() {
this(null, null, null);
}
public ProcessResult(String error) {
this(null, error, null);
}
public ProcessResult(String process, String error, Exception ex) {
setProcess(process);
setException(ex == null ? null : ex.toString());
setError(error);
setExitCode(-1);
}
public boolean isOk() {
return optional || !isWarn();
}
public boolean isWarn() {
return !ZERO.equals(exitCode);
}
public String buildLogMessage() {
return new StringBuilder()
.append("process: ").append(process).append("\r\n")
.append("command: ").append(command).append("\r\n")
.append("exception: ").append(exception).append("\r\n")
.append("error: ").append(error).append("\r\n")
.append("exitValue: ").append(exitCode).append("\r\n")
.append("optional: ").append(optional).append("\r\n")
.append("out: ").append(out).append("\r\n").toString();
}
}
(后面的方法为属性的get和set方法,就没有粘贴了)
定义了一个进程结果类,其中包括属性process(字符串类型)进程名,command(字符串类型)进程命令,exception(字符串类型)异常,error(字符串类型)错误,Integer类型变量exitCode(退出的时候会返回一个数字,一般是-1即表示退出异常,0表示退出正常),字符串类型变量out,以及布尔型变量optional。然后定义了几个构造方法来分别构造ProcessResult对象。
之后的方法为属性的get和set方法便没有粘贴了,isWarn()方法用来判断exitCode是否为0,如果不为0则退出异常发生了错误,返回布尔变量值true。然后isOk()方法通过判断optional或者调用isWarn()取非,来判断是否执行成功,成功返回true。最后的buildLogMessage()返回字符串将该类的属性打印出来供使用者方便读取。
ProcessResultList类
//Collects all results of conversion jobs
public class ProcessResultList {
private List<ProcessResult> jobs = new ArrayList<>();
public void add(ProcessResult res) {
jobs.add(res);
}
public boolean hasError() {
for (ProcessResult res : jobs) {
if (!res.isOk()) {
return true;
}
}
return false;
}
public String getLogMessage() {
StringBuilder logMessage = new StringBuilder();
for (ProcessResult res : jobs) {
logMessage.append("key: ");
logMessage.append(res.getProcess());
logMessage.append("\r\n");
logMessage.append(res.buildLogMessage());
}
return logMessage.toString();
}
public int size() {
return jobs.size();
}
public List<ProcessResult> getJobs() {
return jobs;
}
}
定义了一个List类变量jobs,里面存放的节点是ProcessResult类对象。
add(ProcessResult res)方法即在jobs对象里添加一个节点为参数res。
hasError()方法,调用每个job的isOk()方法,如果有一个exitValue为“-1”的job,返回true。
getLogMessage()方法,通过调用每个job的buildLogMessage()方法,将所有job结果转换为人类可读的格式。
size()方法返回jobs的数量大小。
getJobs()方法即返回jobs这个List。
ProcessHelper类
public class ProcessHelper {
public static final Logger log = Red5LoggerFactory.getLogger(ProcessHelper.class, OpenmeetingsVariables.getWebAppRootKey());
// This is necessary to prevent 'buffer overflow'
// https://stackoverflow.com/questions/9885643/ffmpeg-executed-from-javas-processbuilder-does-not-return-under-windows-7
private static class StreamWatcher extends Thread {
public final StringBuilder output = new StringBuilder();
private final InputStream is;
private boolean run = true;
private StreamWatcher(final InputStream is) {
this.is = is;
}
@Override
public void run() {
try (BufferedReader br = new BufferedReader(new InputStreamReader(is, UTF_8));) {
String line = br.readLine();
while (run && line != null) {
output.append(line).append('\n');
line = br.readLine();
}
} catch (IOException ioexception) {
return;
}
}
public void finish() {
run = false;
}
@Override
public String toString() {
return output.toString();
}
}
private ProcessHelper() {}
private static String getCommand(String[] argv) {
StringBuilder tString = new StringBuilder();
for (int i = 0; i < argv.length; i++) {
tString.append(argv[i]).append(" ");
}
return tString.toString();
}
private static void debugCommandStart(String desc, String[] argv) {
if (log.isDebugEnabled()) {
log.debug("START {} ################# ", desc);
log.debug(getCommand(argv));
}
}
private static void debugCommandEnd(String desc) {
if (log.isDebugEnabled()) {
log.debug("END {} ################# ", desc);
}
}
public static ProcessResult executeScript(String process, String[] argv) {
return executeScript(process, argv, false);
}
public static ProcessResult executeScript(String process, String[] argv, boolean optional) {
Map<String, String> env = new HashMap<>();
return executeScript(process, argv, env, optional);
}
private static ProcessResult executeScript(String process, String[] argv, Map<? extends String, ? extends String> env, boolean optional) {
ProcessResult res = new ProcessResult()
.setProcess(process)
.setOptional(optional);
debugCommandStart(process, argv);
Process proc = null;
StreamWatcher errorWatcher = null;
StreamWatcher inputWatcher = null;
final long start = System.currentTimeMillis();
try {
res.setCommand(getCommand(argv)).setOut("");
ProcessBuilder pb = new ProcessBuilder(argv);
pb.environment().putAll(env);
proc = pb.start();
errorWatcher = new StreamWatcher(proc.getErrorStream());
inputWatcher = new StreamWatcher(proc.getInputStream());
errorWatcher.start();
inputWatcher.start();
proc.waitFor(getExtProcessTtl(), TimeUnit.MINUTES);
res.setExitCode(proc.exitValue())
.setOut(inputWatcher.toString())
.setError(errorWatcher.toString());
} catch (Throwable t) {
log.error("executeScript", t);
res.setExitCode(-1)
.setError(String.format("Exception after %s of work; %s", formatMillis(System.currentTimeMillis() - start), t.getMessage()))
.setException(t.toString());
} finally {
if (proc != null) {
errorWatcher.finish();
inputWatcher.finish();
proc.destroy();
}
}
debugCommandEnd(process);
return res;
}
}
ProcessHelper类首先定义一个Logger日志对象来记录打印,方便调试。
定义了一个内部静态类StreamWatch类继承了线程类Thread,这对于防止“缓冲区溢出”是必要的,内部类定义了StringBuilder类对象output,InputStream类对象is,继承并改写了run方法,利用while循环通过BufferReader类对象调用readLine()方法读取输入的内容,然后output调用append()方法添加到缓冲区中。
后面的getCommand(String[] argv)方法即获取所有的命令参数,返回字符串类型。
然后debugCommandStart()和debugCommandEnd()方法即打印在调试过程中打印开始,调用getCommand方法和打印结束。
之后executeScript(String process, String[] argv, Map<? extends String, ? extends String> env, boolean optional)方法,通过传进来的参数创建一个ProcessResult对象res,调用debugCommandStart()方法,然后通过使用流程Builder,我们可以修改环境变量,方便地设置变量以便在eclipse中运行它,命令执行超时20分钟录音的FFMPEG转换可能需要很长时间才能完成,如果发生了错误则将exitCode设为-1,并且设置错误信息和exception信息,最后调用finish()方法完成该进程。然后调用debugCommandEnd()方法打印该进程调试结束告诉使用者。返回ProcessResult类对象res。
总结
该篇文章将分析src/main下的process文件夹下的类。总共三个类,分别是ProcessResult类、ProcessHelper类和ProcessResultList类,均已分析完毕。后面的文章将继续对main文件下的类进行分析。