Detect when java program fails when being called from bash - java

I have a very simple bash script which calls a java program. I need this bash script to write output to stdout if the java program runs successfully or fails.
#!/bin/bash
if java -jar java_program.jar arg1 ; then echo "run:yes"
else echo "run:no"
fi
if my java program returns
java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at com.redacted.redacted.AdvancedEncryptionStandard.decrypt(AdvancedEncryptionStandard.java:48)
at com.redacted.redacted.App.getStuff(App.java:58)
at com.redacted.redacted.App.main(App.java:27)
My bash script will still return "run:yes". I'm assuming this is because as far as bash is concerned it called the script and it ran. Is there a way for me to decet if the java program actually runs successfully?

Yes, you can. But you must use System.exit(0) from inside your java program to finish the execution and communicate to bash that everything was OK. Just return 1 instead 0 to communicate an error. The response will be stored at $? inside your bash environment to be used at if.
There's another answer on how to use the $? result on bash:
https://unix.stackexchange.com/questions/22726/how-to-conditionally-do-something-if-a-command-succeeded-or-failed

Normally exiting the 'main' method (without explicit exit) will return '0' to the shell. Uncaught exceptions will return status of 1.
javac a
java a
xception in thread "main" java.lang.Exception
at a.main(a.java:4)
echo $?
=> 1
Where a is just
class a {
public static void main(String [] args) throws Exception {
System.out.println("Hello\n") ;
throw new Exception() ;
}
}
On surface, this is a case when the main just catch the exception, print it, and ignore the exception, therefore the calling process return 0
class a {
public static void main(String [] args) {
System.out.println("Hello\n") ;
try {
doSomething() ;
} catch (Exception e) {
e.printStackTrace) ;
} ;
}
}
Few possible approaches: (1) rewrite the main to allow the exception to 'bubble up' and (2) write new main that will execute the old main, and check for success (3) capture stderr, and check for error messages (messy). Otherwise, you are out of luck

Related

How to check if the JAVA Program successfully executed in shell scripting?

I am running java program from shell script. I need to execute next step in same shell script based on if any exception occur in java program or it ran successful.I am aware that java doesn’t run anything. How can we do it in shell script ?
I know that we can print some string in log and grep it to check the status. is there any better way to do this ?
It would be good even if I can get some elegant way to do it using grep.
If a Java program was terminated because of an exception, the JVM will exit with an error status 1, instead of the usual success status 0. For example, this program exits because of a NullPointerException:
shell$ cat Throw.java
public class Throw {
public static void main(String[] args) {
String s = null;
System.out.println(s.length());
}
}
shell$ java Throw 2>/dev/null; echo $?
1
You can use the exit status in a shell if-statement for example. This will print boo:
if java Throw 2>/dev/null ; then
echo woo
else
echo boo
fi
If you want to set an exit code other than 1, use the System.exit(int status) function.

How can I use Powershell's ExitCode to restart a Client/Server pair that I shut down?

I have a simple Java client-server application (code linked on previous Stack question here), that I can run all together with the following Powershell code:
Start-Process java "-cp .;.\lib\commons-io-2.4.jar FixedMessageSequenceServer"
Start-Sleep -Seconds 1
$JavaClient = Start-Process java "-cp .;.\lib\commons-io-2.4.jar FixedMessageSequenceClient -Wait -PassThru"
This works fine. However, I want to add either Powershell code or Java code that would restart the above Powershell code if we force shutdown ( by CTRL-C ) the application (from the Server-side).
I thought that I should be apple to use this code :
if($JavaClient.ExitCode)
{
# exit code is non-zero, better retry
Start-Process java "-cp .;.\lib\commons-io-2.4.jar FixedMessageSequenceServer" -Wait
Start-Process java "-cp .;.\lib\commons-io-2.4.jar FixedMessageSequenceClient -Wait -PassThru"
}
However this does not do anything when I run it. Would I need to append some Java ProcessBuilder code to achieve desired functionality ? Do we need to do processing of the $JavaClient.ExitCode ?
thanks
If you're only evaluating on a single if statement you have a small window for when it can restart even if that code you have did work.
I suggest you create a small polling script that will check the status of a certain process every 10 seconds, 1 minute, etc. and if it isn't running it can start it that way. You could nest this in an infinite loop if the java client should be running at all times, or you could use scheduled tasks to kick off the script if it should be running at a consistent interval/trigger (i.e. top of every hour, etc.)
Try something like this:
if(![bool](get-process java -ErrorAction SilentlyContinue)){
start-process java "-cp .;.\lib\commons-io-2.4.jar FixedMessageSequenceClient -Wait -PassThru"
}
The following code I have works, but it's not very graceful way of doing it:
This is my Java class :
import java.io.*;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class FixedMessageRunner{
public static void main(String[] args) {
// File file = new File("C://Java_Scratch_//Autonomic_Using_Batch//someFile.txt" );
try {
/* StackOverflow code */
for ( ; ; ) {
ProcessBuilder pb = new ProcessBuilder("Powershell ", "WindowsTaskSchedulerPS.PS1");
pb.directory(new File("C://Java_Scratch3_new_cleaned_Mar12//"));
Process p = pb.start();
p.waitFor();
}
/* end - StackOverflow code */
}
catch (IOException i) {
i.printStackTrace();
}
catch (InterruptedException i) {
i.printStackTrace();
}
// end-count_func
}
}
And here is my powershell code, the standard one :
# exit code is non-zero, better retry
Start-Process java "-cp .;.\lib\commons-io-2.4.jar FixedMessageSequenceServer"
Start-Sleep -Seconds 1
Start-Process java "-cp .;.\lib\commons-io-2.4.jar FixedMessageSequenceClient"
When I run the Java code, I need to kill Powershell.exe from the Windows Task Manager, in order to trigger that above waitFor()

JVM on OS X always exiting with status 0 (as captured in Bash script)?

I have a very simple Java class, that does nothing else but:
public class TestMain {
public static void main(String[] args) {
System.out.println("Running!");
System.exit(1111);
}
}
, packed into a TestOSX.jar file.
While on Windows I can run the above snippet and show that %ERRORLEVEL% has the expected value, I get a different outcome on OS X.
Given test.sh containing:
#!/bin/bash
"/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java" -jar TestOSX.jar
wait $!
updater_exit_val=$?
echo $updater_evit_val
, I always print 0.
Setup: OS X 10.11.1, Oracle Java 8 u60.
What trivial detail am I missing here?
You do not send your java process to the background with &. Thus wait is executed after the java process exits. It can't find the process you try to wait for, because it already exited and giving return code 0 because of that. $? returns the return code of the last command (in your case wait).
You can either remove wait from your script, or you send your java process to the background by adding & at the end.

Alternates for System.exit that could send error codes to batch or shell

I have a set of error codes in my java application. Currently I'm using System.exit(code); to return error codes from the application to external applications.
Is there any alternatives of System.exit as using this is bad practice because it may shutdown the entire JVM.
I have shared your experience in the past, and tried to engineer out System.exit(). One possibility is to leave a RuntimeException uncaught and you will return 1 to the shell, but ultimately if you want any more versatility than that (and don't want an ugly stack-trace polluting your output), you must have at least "one" call to System.exit().
public class Splat {
public static void main(String[] args) {
if (args.length > 0 && "splat".equals(args[0]))
throw new RuntimeException("splat");
}
}
Output:
$ java Splat
$ echo $?
> 0
$ java Splat splat
> Exception in thread "main" java.lang.RuntimeException: splat
> at Splat.main(Splat.java:9)
$ echo $?
> 1
My reason for doing this was our organisation started using static analysis results from sonar as a KPI and it was my job to get the numbers down. It's a terrible reason for doing anything, but an interesting engineering challenge nonetheless ....
An approach I tried was throwing a specific class of RuntimeException, with an exit-code instance variable, and catching it at the outer scope. That way you can be sure that when you do murder the VM you're at the tail of the stack anyway ...
public class Splat {
public static final class Exit extends RuntimeException {
private int exitCode;
public Exit(int exitCode) {
this.exitCode = exitCode;
}
}
public static void main(String[] args) {
try {
wrappedMain(args);
} catch (Exit e) {
System.exit(e.exitCode);
}
}
public static void wrappedMain(String[] args) {
if (args.length > 0 && "splat".equals(args[0])) {
int code = (args.length > 1) ? Integer.parseInt(args[1]) : 0;
throw new Exit(code);
}
}
}
Output:
$ java Splat
$ java Splat splat
$ echo $?
> 0
$ java Splat splat 1
$ echo $?
> 1
> $ java Splat splat 2
$ echo $?
> 2
$ java Splat splat -1
$ echo $?
> 127
There are caveats to this approach of course! It is a bit of an odd way to exit and anybody unfamiliar with your constraints will scratch their head. Also, if somebody does catch (Throwable t) later on, then you wont be able to exit!!! If you are working in a static analysis CI environment then that should be quickly highlighted as a more grievous violation!
As already commented: When you wait for some code in a batch or shell you are actually waiting for the program to finish and that means your java program exits and so does the JVM. And the one and only way is then to use System.exit(code) as you are already doing.
If you are talking about the exit code of a process then System.exit(int) is the way to go since you want the whole process to exit and so the JVM should shutdown as well.
But if you want to send out some error messages to the batch or shell (without exiting the process) then you will have to use System.err.println(). This will write to the error stream instead of the output stream.

where does the system.exit() goes to in Java?

It seems this is one way to have a return status code from your main.
but I am wondering where does this int go? I tried it on eclipse, But I do not see it on console.
how do I get the status code
public static void main(String[] args){
int status = 123;
System.exit(status);
}
The exit code is usually returned to a script or program that is running your application, for instance, I wrote the following simple java program
class Test {
public static void main(String[] args) {
System.exit(123);
}
}
I then compiled it using javac Test.java
Next I wrote a simple bash script that would run java Test and then print out the exit code like this
#!/bin/bash
java Test
echo $?
And when i run the bash script the numbers 123 are printed to the screen, as $? is the exit code of the last command that was run.
That value is known as the exit status
The exit status or return code of a process in computer programming is
a small number passed from a child process (or callee) to a parent
process (or caller) when it has finished executing a specific
procedure or delegated task.
Here's a little Java test to demonstrate it
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
public class Foo {
public static void main(String[] args) throws Exception {
if (args.length != 0)
System.exit(Integer.parseInt(args[0]));
ProcessBuilder builder = new ProcessBuilder(Arrays.asList("java", "Foo", "42"));
Process process = builder.start();
System.out.println(process .waitFor());
}
}
compile and run this program without any arguments. It will print
42
This java program starts a child process. When that process ends, it returns the value that was passed to it in System.exit(?) to its parent process which it then prints out.
The exit code (status) is returned to the operating system on termination of the JVM so if you were to run it through terminal/command line you would see if the program terminated abnormally.
C:\JavaTools>javac SystemExit.java
C:\JavaTools>java SystemExit
C:\JavaTools>echo %ERRORLEVEL%
123
The exit code will be returned to the OS. Return 0 means the program exits without an error and vice versa.
Return different error code means different causes. The could help the OS(or parent process) find out what's wrong with the program.

Categories

Resources