Call class, wait for it to exit, call again

139 Views Asked by At

I'm working on a program where I want to loop through several config files, and with each file, call a class with that filename as an argument and wait for it to finish. Currently I am doing:

    for (int i = 1; i <= 3; i++){
        String[] a = new String[1];
        a[0] = "data/config" + i + ".xml";
        edu.cwru.sepia.Main2.class.getMethod("main", String[].class).invoke(null, (Object)a);
    }

However, what happens is that the class only gets called once, and then the entire program stops. I think there is an exit line in the class, but since it is a JAR file I can't be sure and I can't edit it.

Let's assume that is the case; how would I get around that to do what I want? i.e. after the invocation ends with the exiting, my outer loop method continues and just calls the class again with the next argument.

3

There are 3 best solutions below

0
On BEST ANSWER

If the problem is indeed a System.exit() call in the third-party class, you should be able to work around it by following the recommendation in this answer, which provides the following code:

  private static class ExitTrappedException extends SecurityException { }

  private static void forbidSystemExitCall() {
    final SecurityManager securityManager = new SecurityManager() {
      public void checkPermission( Permission permission ) {
        if( "exitVM".equals( permission.getName() ) ) {
          throw new ExitTrappedException() ;
        }
      }
    } ;
    System.setSecurityManager( securityManager ) ;
  }

  private static void enableSystemExitCall() {
    System.setSecurityManager( null ) ;
  }

However, for your purposes it would likely be a better approach to simply spawn a separate Java process for the third-party application and wait for it to terminate. That way you don't have to worry about the third-party code causing side-effects in your JVM instance, or about trying to guess at how to get rid of the side-effects.

0
On

I know of two possibilities how to solve this:

  • You can install a SecurityManager in which you implement the checkExit() method before you call this main() method. This will prevent the System.exit() from actually happening.
  • You can run the method in a separate VM, i.e. starting it using one of the Runtime.exec() methods.

Both have pros and cons. If the jar files mess around with System properties, you may want to go for a separate VM, if they don't, you may want to go for the SecurityManager as that would be less overhead.

1
On

The easiest way to do this is not from Java but from a shell script (or perl/python/ruby script) and just start the VM multiple times.

You can do this from Java too with Runtime.exec or ProcessBuilder.start.

It's not easy to not stop the JVM when System.exit() is called. There is a way to do it though; by installing your own SecurityManager with the System.setSecurityManager call. You can then override the canExit method and throw an Exception (or Error) subclass. However this is not advisable unless you understand the consequences, because it turns on the SecurityManager for the entire JVM which can have unexpected consequences.