1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-06-02 16:40:49 +00:00
plantuml/src/net/sourceforge/plantuml/cucadiagram/dot/ProcessRunner.java

287 lines
6.9 KiB
Java
Raw Normal View History

2010-11-15 20:35:36 +00:00
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
2016-01-09 12:15:40 +00:00
* (C) Copyright 2009-2017, Arnaud Roques
2010-11-15 20:35:36 +00:00
*
2016-03-06 16:47:34 +00:00
* Project Info: http://plantuml.com
2010-11-15 20:35:36 +00:00
*
2017-03-15 19:13:31 +00:00
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
2010-11-15 20:35:36 +00:00
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
2013-12-10 19:36:50 +00:00
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
2010-11-15 20:35:36 +00:00
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.cucadiagram.dot;
2011-02-14 11:56:34 +00:00
import java.io.File;
2010-11-15 20:35:36 +00:00
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
2013-12-10 19:36:50 +00:00
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
2010-11-15 20:35:36 +00:00
2017-04-05 17:37:42 +00:00
import net.sourceforge.plantuml.OptionFlags;
2015-04-07 18:18:37 +00:00
import net.sourceforge.plantuml.api.MyRunnable;
import net.sourceforge.plantuml.api.TimeoutExecutor;
2010-11-15 20:35:36 +00:00
public class ProcessRunner {
2013-12-10 19:36:50 +00:00
private final String[] cmd;
2010-11-15 20:35:36 +00:00
private String error;
private String out;
2015-04-07 18:18:37 +00:00
private volatile ProcessState state = ProcessState.INIT();
2013-12-10 19:36:50 +00:00
private final Lock changeState = new ReentrantLock();
public ProcessRunner(String[] cmd) {
2010-11-15 20:35:36 +00:00
this.cmd = cmd;
}
2011-02-14 11:56:34 +00:00
2015-04-07 18:18:37 +00:00
public ProcessState run(byte in[], OutputStream redirection) {
return run(in, redirection, null);
2011-02-14 11:56:34 +00:00
}
2015-04-07 18:18:37 +00:00
public ProcessState run(byte in[], OutputStream redirection, File dir) {
if (this.state.differs(ProcessState.INIT())) {
2013-12-10 19:36:50 +00:00
throw new IllegalStateException();
}
2015-04-07 18:18:37 +00:00
this.state = ProcessState.RUNNING();
2013-12-10 19:36:50 +00:00
final MainThread mainThread = new MainThread(cmd, dir, redirection, in);
try {
2017-04-05 17:37:42 +00:00
// http://steveliles.github.io/invoking_processes_from_java.html
final long timeoutMs = OptionFlags.getInstance().getTimeoutMs();
final boolean done = new TimeoutExecutor(timeoutMs).executeNow(mainThread);
2013-12-10 19:36:50 +00:00
} finally {
changeState.lock();
try {
2015-04-07 18:18:37 +00:00
if (state.equals(ProcessState.RUNNING())) {
state = ProcessState.TIMEOUT();
// mainThread.cancel();
2013-12-10 19:36:50 +00:00
}
} finally {
changeState.unlock();
}
}
2015-04-07 18:18:37 +00:00
if (state.equals(ProcessState.TERMINATED_OK())) {
2013-12-10 19:36:50 +00:00
assert mainThread != null;
this.error = mainThread.getError();
this.out = mainThread.getOut();
}
return state;
2010-11-15 20:35:36 +00:00
}
2015-04-07 18:18:37 +00:00
class MainThread implements MyRunnable {
2010-11-15 20:35:36 +00:00
2013-12-10 19:36:50 +00:00
private final String[] cmd;
private final File dir;
2010-11-15 20:35:36 +00:00
private final OutputStream redirection;
2013-12-10 19:36:50 +00:00
private final byte[] in;
private volatile Process process;
private volatile ThreadStream errorStream;
private volatile ThreadStream outStream;
public MainThread(String[] cmd, File dir, OutputStream redirection, byte[] in) {
this.cmd = cmd;
this.dir = dir;
this.redirection = redirection;
this.in = in;
}
public String getOut() {
return outStream.getString();
}
public String getError() {
return errorStream.getString();
}
2015-04-07 18:18:37 +00:00
public void runJob() throws InterruptedException {
2013-12-10 19:36:50 +00:00
try {
2015-04-07 18:18:37 +00:00
startThreads();
if (state.equals(ProcessState.RUNNING())) {
2013-12-10 19:36:50 +00:00
final int result = joinInternal();
}
} finally {
changeState.lock();
try {
2015-04-07 18:18:37 +00:00
if (state.equals(ProcessState.RUNNING())) {
state = ProcessState.TERMINATED_OK();
2013-12-10 19:36:50 +00:00
}
} finally {
changeState.unlock();
}
if (process != null) {
process.destroy();
close(process.getErrorStream());
close(process.getOutputStream());
close(process.getInputStream());
}
}
}
2015-04-07 18:18:37 +00:00
public void cancelJob() {
2013-12-10 19:36:50 +00:00
// The changeState lock is ok
2015-04-07 18:18:37 +00:00
// assert changeState.tryLock();
// assert state == ProcessState.TIMEOUT;
2013-12-10 19:36:50 +00:00
if (process != null) {
errorStream.cancel();
outStream.cancel();
process.destroy();
2015-04-07 18:18:37 +00:00
// interrupt();
2013-12-10 19:36:50 +00:00
close(process.getErrorStream());
close(process.getOutputStream());
close(process.getInputStream());
}
}
2015-04-07 18:18:37 +00:00
private void startThreads() {
2013-12-10 19:36:50 +00:00
try {
process = Runtime.getRuntime().exec(cmd, null, dir);
} catch (IOException e) {
2015-04-07 18:18:37 +00:00
e.printStackTrace();
2013-12-10 19:36:50 +00:00
changeState.lock();
try {
2015-04-07 18:18:37 +00:00
state = ProcessState.IO_EXCEPTION1(e);
2013-12-10 19:36:50 +00:00
} finally {
changeState.unlock();
}
e.printStackTrace();
return;
}
errorStream = new ThreadStream(process.getErrorStream(), null);
outStream = new ThreadStream(process.getInputStream(), redirection);
errorStream.start();
outStream.start();
if (in != null) {
final OutputStream os = process.getOutputStream();
try {
try {
os.write(in);
} finally {
os.close();
}
} catch (IOException e) {
changeState.lock();
try {
2015-04-07 18:18:37 +00:00
state = ProcessState.IO_EXCEPTION2(e);
2013-12-10 19:36:50 +00:00
} finally {
changeState.unlock();
}
e.printStackTrace();
}
}
}
public int joinInternal() throws InterruptedException {
errorStream.join();
outStream.join();
final int result = process.waitFor();
return result;
}
}
class ThreadStream extends Thread {
private volatile InputStream streamToRead;
private volatile OutputStream redirection;
private volatile StringBuffer sb = new StringBuffer();
2010-11-15 20:35:36 +00:00
ThreadStream(InputStream streamToRead, OutputStream redirection) {
this.streamToRead = streamToRead;
this.redirection = redirection;
}
2013-12-10 19:36:50 +00:00
public String getString() {
2017-04-05 17:37:42 +00:00
if (sb == null) {
2015-04-07 18:18:37 +00:00
return "";
}
2013-12-10 19:36:50 +00:00
return sb.toString();
}
public void cancel() {
2015-04-07 18:18:37 +00:00
assert state.equals(ProcessState.TIMEOUT()) || state.equals(ProcessState.RUNNING()) : state;
2013-12-10 19:36:50 +00:00
this.interrupt();
sb = null;
streamToRead = null;
redirection = null;
// Because of this, some NPE may occurs in run() method, but we do not care
}
2010-11-15 20:35:36 +00:00
@Override
public void run() {
int read = 0;
try {
while ((read = streamToRead.read()) != -1) {
2015-04-07 18:18:37 +00:00
if (state.equals(ProcessState.TIMEOUT())) {
2013-12-10 19:36:50 +00:00
return;
}
2010-11-15 20:35:36 +00:00
if (redirection == null) {
sb.append((char) read);
} else {
redirection.write(read);
}
}
2013-12-10 19:36:50 +00:00
} catch (Throwable e) {
2015-04-07 18:18:37 +00:00
System.err.println("ProcessRunnerA " + e);
2010-11-15 20:35:36 +00:00
e.printStackTrace();
sb.append('\n');
sb.append(e.toString());
}
}
}
public final String getError() {
return error;
}
public final String getOut() {
return out;
}
2013-12-10 19:36:50 +00:00
private void close(InputStream is) {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void close(OutputStream os) {
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
2010-11-15 20:35:36 +00:00
}