3

My Goal


I am attempting to make a Java program in which a user can select any .class or .jar file from their computer. My program will then pop up a JInternalFrame with a JEditorPane in it as the console, capturing any console output from the user's program. When the user's program closes (calls System.exit(int status);), my program must not close along with it. My program might also have such features as a button to immediately stop the user's program and others an IDE would. My program need not compile Java code, only run .class and .jar files.

My Experience


I have made a small test version of this program wherein I got two specific files from a package and had the user click one of two buttons, each representing one of the two programs. A press of a button calls the following method:

  private void run(Class runnable)
  {
    java.lang.reflect.Method[] m = runnable.getMethods();
    boolean hasMain = false;
    for (int i = 0; i < m.length; i++)
    {
      if (m[i].getName().equals("main") && m[i].getParameterTypes()[0].isArray() && m[i].getParameterTypes()[0].getName().contains("java.lang.String"))
        try
        {
          Object invoke = m[i].invoke(null, (Object)globalArgs);
          hasMain = true;
          hub.setExtendedState(Hub.ICONIFIED);
          numPrograms++;
        }
        catch (Throwable t)
        {
          java.util.logging.Logger.getLogger(Hub.class.getName()).log(java.util.logging.Level.SEVERE, null, t);
          javax.swing.JOptionPane.showMessageDialog(null, "Could not run " + runnable.getName(), "Error in invocation", javax.swing.JOptionPane.ERROR_MESSAGE);
        }
        finally
        {
          break;
        }
    }
    if (!hasMain)
      javax.swing.JOptionPane.showMessageDialog(null, runnable.getName()
                                                      + " does not have a public static main method that\nreturns void and takes in an array of Strings",
                                                "No main method", javax.swing.JOptionPane.ERROR_MESSAGE);
  }

This method successfully calls either program's main method and runs a copy of said program. However, when any of the programs this hub has started calls the System.exit(int status) command, the hub closes, too. Also, I haven't the slightest clue as to how to capture console output.

My Questions


Does anyone have any experience or advice they would be willing to share to help me make a fully-functional program that can...

  1. Open and run a compiled Java file (remember that .jar files may have more than one class with main(String[] args) method)
  2. Catch System.exit(int status); so that the hub program handles the internal program's exiting
  3. Catch new java.io.PrintStream().println(Object o) and similar calls and place their output in a JEditorPane
  4. Make a button that, when pressed, stops the internal program from running
  5. Possibly make all JFrames the internal program uses into JInternalFrames and place them in a JDesktopPane
Ky -
  • 30,724
  • 51
  • 192
  • 308

1 Answers1

7

If you don't want the other program (which you call through it's main method) to be able to shut down the JVM you're running in, you have, as I see it, three options:

1. Using a SecurityManager

Set up the SecurityManager so that it prevents the System.exit call:

public class Test {
    public static void main(String args[]) {
        SecurityManager sm = System.getSecurityManager();
        System.setSecurityManager(new SecurityManager() {
            @Override
            public void checkExit(int status) {
                throw new SecurityException("Client program exited.");
            }
        });

        try {
            System.out.println("hello");
            System.exit(0);
            System.out.println("world");
        } catch (SecurityException se) {
            System.out.println(se.getMessage());
        }
    }
}

Prints:

hello
Client program exited.

This is probably the nicest solution. This is the way application servers prevent an arbitrary servlet from terminating the entire server.

2. Separate JVM

Run the other program in a separate JVM, using for instance ProcessBuilder

import java.io.*;

public class Test {
    public static void main(String args[]) throws IOException {

        ProcessBuilder pb = new ProcessBuilder("java", "other.Program");
        pb.redirectErrorStream();
        Process p = pb.start();
        InputStream is = p.getInputStream();
        int ch;
        while ((ch = is.read()) != -1)
            System.out.print((char) ch);
        is.close();
        System.out.println("Client program done.");
    }
}

3. Use shutdown hooks instead

Don't disallow the termination of the JVM, but instead add shutdown-hooks that cleans up the "hub" and exits gracefully. (This option probably only makes sense if your running one "external" program at a time.)

import java.io.*;

public class Test {

    public static void main(String args[]) throws IOException {

        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() { 
                System.out.println("Uninitializing hub...");
                System.out.println("Exiting gracefully.");
            }
        });

        // Run client program
        System.out.println("Running... running... running...");
        System.exit(0);

     }
}

Prints:

Running... running... running...
Uninitializing hub...
Exiting gracefully.
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • SecurityManager is most likely the best bet. – Thorbjørn Ravn Andersen Oct 23 '10 at 08:08
  • I like the first option, but how will the hub program exit, then? – Ky - Oct 23 '10 at 08:19
  • I have listed all my questions if you care to look at them, again – Ky - Oct 24 '10 at 12:59
  • just saying: I won't accept your answer because it only answers one of my questions. – Ky - Oct 27 '10 at 04:09
  • I really think you should post one question per question. I don't think anyone will have the energy to answer all of your questions in one post. I have ideas for solutions on question 3 and 4, but I see no point in spending time with it since I don't have answers on all your questions. – aioobe Oct 27 '10 at 08:22
  • For the sake of helping, please post your answers. I'll probably accept this answer if it answers enough questions. And again, how would I exit the hub if I implement the first one? – Ky - Oct 28 '10 at 18:32
  • Another reason for splitting 5 question up into 5 stackoverflow-questions is that it get more accessible to other people coming from for instance google. – aioobe Oct 28 '10 at 19:45
  • This one and http://stackoverflow.com/questions/4050036/how-do-i-open-and-run-a-compiled-java-file (more to come) – Ky - Oct 29 '10 at 07:59
  • http://stackoverflow.com/questions/4054860/make-a-button-that-when-pressed-stops-an-internal-program-from-running – Ky - Oct 29 '10 at 18:45
  • http://stackoverflow.com/questions/4055303/how-do-i-catch-a-java-io-printstream-place-its-output-in-a-jeditorpane – Ky - Oct 29 '10 at 19:39
  • http://stackoverflow.com/questions/4055467/is-it-possible-make-all-jframes-the-internal-program-uses-into-jinternalframes-an – Ky - Oct 29 '10 at 20:05
  • http://stackoverflow.com/questions/4055652/how-do-i-make-a-java-io-file-into-a-java-lang-class-to-run-it – Ky - Oct 29 '10 at 20:29