Permalink
Browse files

Merge branch 'master' into native-clamp

  • Loading branch information...
LadyCailin committed Jan 18, 2019
2 parents 1354702 + db7182a commit 1d5e51d70a9e629275cad718bf6989e4709df737
@@ -4,15 +4,19 @@
import com.laytonsmith.PureUtilities.Common.StringUtils;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.input.CloseShieldInputStream;
import org.apache.commons.io.output.CloseShieldOutputStream;

/**
* Contains utilities to execute an external process and retrieve various results from it.
@@ -26,6 +30,8 @@
*
* @param command
* @return
* @throws java.lang.InterruptedException
* @throws java.io.IOException
*/
public static String Execute(String command) throws InterruptedException, IOException {
return Execute(StringToArray(command));
@@ -37,6 +43,8 @@ public static String Execute(String command) throws InterruptedException, IOExce
*
* @param args
* @return
* @throws java.lang.InterruptedException
* @throws java.io.IOException
*/
public static String Execute(String[] args) throws InterruptedException, IOException {
final List<Byte> output = new ArrayList<>();
@@ -53,7 +61,7 @@ public void write(int next) throws IOException {
c.waitFor();
byte[] bytes = new byte[output.size()];
for(int i = 0; i < output.size(); i++) {
bytes[i] = output.get(i).byteValue();
bytes[i] = output.get(i);
}

return new String(bytes, "UTF-8");
@@ -94,93 +102,92 @@ public CommandExecutor start() throws IOException {
ProcessBuilder builder = new ProcessBuilder(args);
builder.directory(workingDir);
process = builder.start();
outThread = new Thread(new Runnable() {

@Override
public void run() {
InputStream bout = new BufferedInputStream(process.getInputStream());
int ret;
try {
while((ret = bout.read()) != -1) {
if(out != null) {
out.write(ret);
}
}
outThread = new Thread(() -> {
int ret;
try(InputStream bout = new BufferedInputStream(process.getInputStream());) {
while((ret = bout.read()) != -1) {
if(out != null) {
out.flush();
out.write(ret);
}
} catch (IOException ex) {
Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if(out != null) {
try {
out.close();
} catch (IOException ex) {
Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex);
}
}
if(out != null) {
out.flush();
}
} catch(IOException ex) {
Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if(out != null) {
try {
out.close();
} catch(IOException ex) {
Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}, Arrays.toString(args) + "-output");
outThread.start();
errThread = new Thread(new Runnable() {

@Override
public void run() {
InputStream berr = new BufferedInputStream(process.getErrorStream());
int ret;
try {
while((ret = berr.read()) != -1) {
if(err != null) {
err.write(ret);
}
}
errThread = new Thread(() -> {
int ret;
try(InputStream berr = new BufferedInputStream(process.getErrorStream());) {
while((ret = berr.read()) != -1) {
if(err != null) {
err.flush();
err.write(ret);
}
} catch (IOException ex) {
Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if(err != null) {
try {
err.close();
} catch (IOException ex) {
Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex);
}
}
if(err != null) {
err.flush();
}
} catch(IOException ex) {
Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if(err != null) {
try {
err.close();
} catch(IOException ex) {
Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}, Arrays.toString(args) + "-error");
errThread.start();
if(in != null) {
inThread = new Thread(new Runnable() {

@Override
public void run() {
OutputStream bin = new BufferedOutputStream(process.getOutputStream());
int ret;
try {
while((ret = in.read()) != -1) {
bin.write(ret);
}
} catch (IOException ex) {
Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if(in != null) {
try {
in.close();
} catch (IOException ex) {
Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex);
inThread = new Thread(() -> {
OutputStream bin = new BufferedOutputStream(process.getOutputStream());
try(BufferedReader br = new BufferedReader(new InputStreamReader(in));) {
// This is necessary, because InputStream.read() blocks forever, and
// is not interruptable, so to prevent memory leaks, we must unfortunately
// busy wait.
while(!inThread.isInterrupted()) {
if(br.ready()) {
int ret;
if((ret = br.read()) != -1) {
bin.write(ret);
}
}
try {
Thread.sleep(10);
} catch(InterruptedException ex) {
// Will pick up in the while loop.
inThread.interrupt();
}
}
} catch(IOException ex) {
Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex);
}
}, Arrays.toString(args) + "-input");
inThread.start();
}
return this;
}

/**
* Sets the InputStream for the program. If passing in {@code System.in}, it's important to note that you should
* wrap this in a {@link CloseShieldInputStream}, as the code in general will attempt to close all streams after the
* program is done.
*
* @param input
* @return
*/
public CommandExecutor setSystemIn(InputStream input) {
if(process != null) {
throw new RuntimeException("Process is already started! Cannot set a new InputStream!");
@@ -189,6 +196,14 @@ public CommandExecutor setSystemIn(InputStream input) {
return this;
}

/**
* Sets the standard OutputStream for the program. If passing in {@code System.out} or {@code System.err},
* it's important to note that you
* should wrap this in a {@link CloseShieldOutputStream}, as the code in general will attempt to close all streams
* after the program is done.
* @param output The output stream
* @return {@code this} for chaining.
*/
public CommandExecutor setSystemOut(OutputStream output) {
if(process != null) {
throw new RuntimeException("Process is already started! Cannot set a new InputStream!");
@@ -197,6 +212,14 @@ public CommandExecutor setSystemOut(OutputStream output) {
return this;
}

/**
* Sets the error OutputStream for the program. If passing in {@code System.err} or {@code System.out},
* it's important to note that you
* should wrap this in a {@link CloseShieldOutputStream}, as the code in general will attempt to close all streams
* after the program is done.
* @param error The output stream
* @return {@code this} for chaining
*/
public CommandExecutor setSystemErr(OutputStream error) {
if(process != null) {
throw new RuntimeException("Process is already started! Cannot set a new OutputStream!");
@@ -237,31 +260,37 @@ public int waitFor() throws InterruptedException {
if(out != null) {
try {
out.flush();
} catch (IOException ex) {
} catch(IOException ex) {
Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex);
}
}
if(err != null) {
try {
err.flush();
} catch (IOException ex) {
} catch(IOException ex) {
Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex);
}
}
outThread.join();
errThread.join();
if(inThread != null) {
inThread.interrupt();
}
return ret;
}

/**
* Sets the inputs and outputs to be System.in, StreamUtils.GetSystemOut(), and StreamUtils.GetSystemErr().
* <p>
* System.in is wrapped in a {@link CloseShieldInputStream}, so it won't be accidentally closed, and likewise
* out and err are wrapped in {@link CloseShieldOutputStream}.
*
* @return
*/
public CommandExecutor setSystemInputsAndOutputs() {
setSystemOut(StreamUtils.GetSystemOut());
setSystemErr(StreamUtils.GetSystemErr());
setSystemIn(System.in);
setSystemOut(new CloseShieldOutputStream(StreamUtils.GetSystemOut()));
setSystemErr(new CloseShieldOutputStream(StreamUtils.GetSystemErr()));
setSystemIn(new CloseShieldInputStream(System.in));
return this;
}

@@ -1,6 +1,7 @@
package com.laytonsmith.PureUtilities;

import java.io.File;
import java.io.IOException;

/**
* This class contains several constant file locations, which can be used throughout the rest of the application. It
@@ -18,22 +19,29 @@
private static final File USER_HOME;
private static final File USER_DIR;
private static final File JAVA_HOME;
private static final File TEMP_DIR;

static {
File userHome = null;
File userDir = null;
File javaHome = null;
File tempDir = null;
try {
userHome = new File(System.getProperty("user.home"));
userDir = new File(System.getProperty("user.dir"));
javaHome = new File(System.getProperty("java.home"));
} catch (SecurityException e) {
File tmp = File.createTempFile("FileLocationTempFile", ".tmp");
tempDir = tmp.getParentFile();
tmp.delete();
tmp.deleteOnExit();
} catch (SecurityException | IOException e) {
//This could happen in applets or some other wierd security configuration.
//Regardless, we don't want this to ever fail.
}
USER_HOME = userHome;
USER_DIR = userDir;
JAVA_HOME = javaHome;
TEMP_DIR = tempDir;
}

/**
@@ -84,4 +92,12 @@ public File getUserDir() {
public File getJavaHome() {
return JAVA_HOME;
}

/**
* Returns the location of the system's temporary directory.
* @return
*/
public File getTempDir() {
return TEMP_DIR;
}
}
Oops, something went wrong.

0 comments on commit 1d5e51d

Please sign in to comment.