I have a project that uses ProcessBuilder to capture the output of the command "java -jar someJar.jar -argument", but have now moved the jar's source files to a separate package; somepackage. The package has a main function, so I would like to create a ProcessBuilder that captures the output of that process, as if it were a different Thread.
Is this possible, or will I have to completely re-write the code to allow it to use the source files instead of the binary?
If I'm assuming right, the package has main function and we are trying to get output of the main method that executes with java -jar processbuilder command.
ProcessBuilder pb = new ProcessBuilder(your java -jar command);
Process process = pb .start();
process.waitFor();
BufferedInputStream in = new BufferedInputStream(process.getInputStream());
byte[] contents = new byte[1024];
int jwtOytputBytesRead = 0;
String Output = "";
while ((jwtOytputBytesRead = in.read(contents)) != -1) {
Output += new String(contents, 0, jwtOytputBytesRead);
}
System.out.println(Output);
Try this link as well to specify the main the class
Run class in Jar file
Related
I am trying to run a .jar from within my Java program. I am using ProcessBuilder to do so, but it is not working correctly.
I am wondering if I am missing something.
This is what I currently have that is trying to run the .jar
ProcessBuilder pb = new ProcessBuilder("java", "-jar", System.getProperty("user.home") + "/JARFile/JARFile.jar");
Process p = pb.start();
I have the directory correct, so I am not positive why this is not working properly.
Do I have something wrong with my parameters in the new ProcessBuilder?
1) in third argument set full path to file:
ProcessBuilder pb = new ProcessBuilder("java", "-jar",
"/home/meiskalt7/Documents/runJar-55056616-1.0-SNAPSHOT.jar");
Result will be look like this:
public static void main(String[] args) throws IOException {
ProcessBuilder pb = new ProcessBuilder("java", "-jar",
"/home/meiskalt7/Documents/runJar-55056616-1.0-SNAPSHOT.jar");
Process p = pb.start();
InputStream in = p.getInputStream();
System.out.println(new BufferedReader(new InputStreamReader(in))
.lines().collect(Collectors.joining("\n")));
}
and in console you will see result of execution
2) If everything will be good then you must check your system property with
System.out.println(System.getProperty("user.home"))
and if path looks like path in first step then you must compare path with equals operator:
System.out.println((System.getProperty("user.home") + "/JARFile/JARFile.jar")
.equals([YOUR FULL PATH]))
Maybe your problem with symbols of another language in path
2*) if something go wrong then you can check error of process execution in error stream of your process:
InputStream err = p.getErrorStream();
System.out.println(new BufferedReader(new InputStreamReader(err))
.lines().collect(Collectors.joining("\n")));
I need to start a server using bash, so I had created an UNIX shell , but I am not able to execute it with Java from Eclipse.
I tried the following code which doesn't work :
Process proc = Runtime.getRuntime().exec(./startServer);
Here is content of the startServer file :
#!/bin/bash
cd /Users/sujitsoni/Documents/bet/client
npm start
You can try the following two options.
Option 1
Process proc = Runtime.getRuntime().exec("/bin/bash", "-c", "<Abosulte Path>/startServer");
Option 2
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", "<Absolute Path>/startServer");
pb.directory(new File("<Absolute Path>"));
Process proc = pb.start();
A couple Of things can go wrong:
The path to the file you have given might be wrong for eclipse it can take relative path but from the command line, it will take the absolute path.
error=13, Permission denied - If the script file doesn't have required permissions. In your scenario, that might not the case as you are not getting any error.
At last, you are executing the script by java program so the output of your script will not be printed out. In your scenario, this might be the case. You need to capture the output of script from BufferedReade and print it. ( In your case server might have started but you are not seeing the logs/output of the script.
See the code sample below for printing output.
public static void main(String[] args) throws IOException, InterruptedException {
Process proc = Runtime.getRuntime().exec("./startServer");
proc.waitFor();
StringBuffer output = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
System.out.println(output);
}
When I run a bach script containing "echo $Path" command what it outputs when run by java is different from what it outputs when run from command line. It also affects other commands of my script. Why is this happening and how do I avoid?
Following is my function to run a bashscript
public static String executeCommands(File tempScript, Boolean deleteFile)
throws IOException, InterruptedException {
StringBuffer output = new StringBuffer();
try {
ProcessBuilder pb = new ProcessBuilder("bash", tempScript.toString());
pb.inheritIO();
Process process = pb.start();
process.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
return line;
} finally {
if (deleteFile == true)
tempScript.delete();
}
}
when the script contains "echo $PATH" in bashscript
output is
/usr/bin:/bin:/usr/sbin:/sbin
But when I run from commandline output is
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/scala/scala-2.11.8/bin:/Users/<user>/Installations/activator-dist-1.3.10
When we run the command from terminal it reads the environment variables from .bashrc file, but it seems eclipse does not read environment variables from .bashrc.
launch eclipse with ./eclipse -DPATH=$PATH to read from bashrc
PATH variable from
1.terminal
user#ubuntu:~$ javac SS47.java
user#ubuntu:~$ java SS47
/home/user/perl5/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/user/apache-maven-3.3.3/bin:/home/user/apache-maven-3.3.3/bin:/opt/jdk/jdk1.8.0_60/bin:/opt/jdk/jdk1.8.0_60/jre/bin:/home/user/dsc-cassandra-2.1.6/bin:/home/user/hadoop-2.6.0/bin:/home/user/hadoop-2.6.0/sbin:/home/user/android/android-studio/bin:/home/user/android/android-sdk-linux/platform-tools:/home/user/elasticsearch-2.3.5/bin:/home/user/scala-2.11.8/bin::/home/user/apache-maven-3.3.3/bin
2.eclipse with out $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
3.eclipse with PATH ./eclipse -DPATH=$PATH
/home/user/perl5/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/user/apache-maven-3.3.3/bin:/home/user/apache-maven-3.3.3/bin:/opt/jdk/jdk1.8.0_60/bin:/opt/jdk/jdk1.8.0_60/jre/bin:/home/user/dsc-cassandra-2.1.6/bin:/home/user/hadoop-2.6.0/bin:/home/user/hadoop-2.6.0/sbin:/home/user/android/android-studio/bin:/home/user/android/android-sdk-linux/platform-tools:/home/user/elasticsearch-2.3.5/bin:/home/user/scala-2.11.8/bin::/home/user/apache-maven-3.3.3/bin
As Elliott-Frisch pointed out in his comment, just call bash with the option -l which
Make[s] bash act as if it had been invoked as a login shell (see INVOCATION below). Source
This way you don't have to call Eclipse with different launch options etc. and it makes your solution independent, being able to be run without the non customized Eclipse or just bare-bone JRE.
So just edit your call ProcessBuilder like this:
ProcessBuilder pb = new ProcessBuilder("bash", "-l", tempScript.toString());
I need to pipe a text argument to the stdin of a command launched with Apache Commons Exec (for the curious, the command is gpg and the argument is the passphrase to the keystore; gpg does not have an argument to provide the passphrase explicitly, only to accept it from stdin).
In addition, I need this to support both Linux and Windows.
In a shell script I'd do
cat mypassphrase|gpg --passphrase-fd
or
type mypassphrase|gpg --passphrase-fd
but type doesn't work on Windows as it's not an executable but a command built into the command interpreted (cmd.exe).
The code not working (for the above reason) is below. To spawn an entire shell for this is too ugly, I was looking for a more elegant solution. Unfortunately, there are some incompatibility problems between the BouncyCastle library and PGP so I cannot use a fully programmatic solution in the (very short) time I have.
Thanks in advance.
CommandLine cmdLine = new CommandLine("type");
cmdLine.addArgument(passphrase);
cmdLine.addArgument("|");
cmdLine.addArgument("gpg");
cmdLine.addArgument("--passphrase-fd");
cmdLine.addArgument("0");
cmdLine.addArgument("--no-default-keyring");
cmdLine.addArgument("--keyring");
cmdLine.addArgument("${publicRingPath}");
cmdLine.addArgument("--secret-keyring");
cmdLine.addArgument("${secretRingPath}");
cmdLine.addArgument("--sign");
cmdLine.addArgument("--encrypt");
cmdLine.addArgument("-r");
cmdLine.addArgument("recipientName");
cmdLine.setSubstitutionMap(map);
DefaultExecutor executor = new DefaultExecutor();
int exitValue = executor.execute(cmdLine);
You cannot add a pipe argument (|) because the gpg command won't accept that. It's the shell (e.g. bash) that interprets the pipe and does special processing when you type that commandline into the shell.
You can use ByteArrayInputStream to manually send data to the standard input of a command (much like bash does when it sees the |).
Executor exec = new DefaultExecutor();
CommandLine cl = new CommandLine("sed");
cl.addArgument("s/hello/goodbye/");
String text = "hello";
ByteArrayInputStream input =
new ByteArrayInputStream(text.getBytes("ISO-8859-1"));
ByteArrayOutputStream output = new ByteArrayOutputStream();
exec.setStreamHandler(new PumpStreamHandler(output, null, input));
exec.execute(cl);
System.out.println("result: " + output.toString("ISO-8859-1"));
This should be the equivalent of typing echo "hello" | sed s/hello/goodbye/ into a (bash) shell (though UTF-8 may be a more appropriate encoding).
Hi to do this i will use a little helper class like this: https://github.com/Macilias/Utils/blob/master/ShellUtils.java
basically you can than simulate the pipe usage like shown here before without calling the bash beforehand:
public static String runCommand(String command, Optional<File> dir) throws IOException {
String[] commands = command.split("\\|");
ByteArrayOutputStream output = null;
for (String cmd : commands) {
output = runSubCommand(output != null ? new ByteArrayInputStream(output.toByteArray()) : null, cmd.trim(), dir);
}
return output != null ? output.toString() : null;
}
private static ByteArrayOutputStream runSubCommand(ByteArrayInputStream input, String command, Optional<File> dir) throws IOException {
final ByteArrayOutputStream output = new ByteArrayOutputStream();
CommandLine cmd = CommandLine.parse(command);
DefaultExecutor exec = new DefaultExecutor();
if (dir.isPresent()) {
exec.setWorkingDirectory(dir.get());
}
PumpStreamHandler streamHandler = new PumpStreamHandler(output, output, input);
exec.setStreamHandler(streamHandler);
exec.execute(cmd);
return output;
}
i have a .jar file, which I can run on the command line:
java -jar myFile.jar argument1
I want to save the output of this .jar as a String variable inside another java program.
How can I do it?
I tried including myFile.jar as a reference in my program, and doing myFile.main(new String{"argument1"}) in my program. But this just prints the results to console, I can't use the results in my program.
Hope this is not too confusing.
I
Running Jar file require you to have the jar file included in your class path. This can be done at run time using URLClassLoader. Simply construct a URLClassLoader with the jar as one of the URL. Then call its forClass(...) if you know the class name (full name of course). Or inspect the manifest file using its 'findResources(String name)'.
Once you get the class, you can use reflection to get its static method main.
Seeing your question again, you know the class name, so if you are sure the jar file in already in the class path, then you can just call it as you tried.
II
To capture the output, you can call System.setOut(PrintStream out) and System.setErrPrintStream out) to change the print stream. You can pass the printstream that you create. Like this:
ByteArrayOutputStream BAOS = new ByteArrayOutputStream();
PrintStream MyOut = new PrintStream(BAOS);
System.setOut(MyOut);
// Do something to have something printed out.
...
String TheCaptured = new String(BAOS.toByteArray());
Hope this helps.
If you can't include the other jar,
you can use something like that
Runtime re = Runtime.getRuntime();
BufferedReader output;
try{
cmd = re.exec("java -jar MyFile.jar" + argument);
output = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
} catch (IOException ioe){
ioe.printStackTrace();
}
String resultOutput = output.readLine();
I know my code isn't perfect like the catching exception, etc but I think this could give you a good idea.
Being a Jar file, you can add it to your class path and call the functionality of the program your self. You might need to know more about the logic behind the Jar to use it without having it output the information..
I believe what you are looking for is how to shell execute the Jar archive. An example can be found here.
Take a look at ProcessBuilder:
http://java.sun.com/javase/6/docs/api/java/lang/ProcessBuilder.html
It effectively creates an operating system process which you can then capture the output from using:
process.getInputStream().
The line:
processbuilder.redirectErrorStream(true)
will merge the output stream and the error stream in the following example:
e.g.
public class ProcessBuilderExample {
public ProcessBuilderExample() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("java", "-jar", "gscale.jar");
pb.redirectErrorStream(true);
pb.directory(new File("F:\\Documents and Settings\\Administrator\\Desktop"));
System.out.println("Directory: " + pb.directory().getAbsolutePath());
Process p = pb.start();
InputStream is = p.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
for (String line = br.readLine(); line != null; line = br.readLine()) {
System.out.println( line ); // Or just ignore it
}
p.waitFor();
}
}