Submitted by patrick on Thu, 02/03/2011 - 16:04
Posted in
Seems like Java developers shun the idea of having to do anything out of their cozy virtual machine, so I couldn't find any good code examples for doing this problem: Fork a new JVM from your current JVM and capture it's stdout/stderr stream to a JTextArea. Allow the user to kill the subprocess at any time.
Well, here's my solution:
import java.awt.event.*; import javax.swing.event.*; import javax.swing.*; import java.io.*; public class ForkDemo implements ActionListener { protected JTextArea output = new JTextArea(10,20); protected JButton start = new JButton("START"); protected JButton stop = new JButton("STOP"); private ForkWorker forkWorker; public ForkDemo() {} public void actionPerformed(ActionEvent e) { if (e.getSource()==start) { doStart(); } if (e.getSource()==stop) { doStop(); } } private void doStart() { StringBuilder sb = new StringBuilder(System.getProperty("java.home")); sb.append(File.separator); sb.append("bin"); sb.append(File.separator); sb.append("java"); File jvm = new File(sb.toString()); if (! jvm.exists()) { // Guess which OS we are on... sb.append(".exe"); } ProcessBuilder builder = new ProcessBuilder(sb.toString(), "my.classname"); builder.redirectErrorStream(true); forkWorker = new ForkWorker(output,builder); forkWorker.execute(); } private void doStop() { if (forkWorker!=null) { forkWorker.cancel(true); } } public static void main(String[] args) { ForkDemo demo = new ForkDemo(); demo.start.addActionListener(demo); demo.stop.addActionListener(demo); JFrame frame = new JFrame(); JPanel content = new JPanel(); content.add(new JScrollPane(demo.output)); content.add(demo.start); content.add(demo.stop); frame.setContentPane(content); frame.pack(); frame.setVisible(true); } }
And now the actual workhorse:
import javax.swing.*; import java.awt.*; import java.io.*; import java.util.*; class ForkWorker extends SwingWorker<String,String> { private JTextArea output; // Where to redirect STDERR & STDOUT to private ProcessBuilder builder; public ForkWorker(JTextArea output, ProcessBuilder builder) { this.output=output; this.builder= builder; } protected void process(java.util.List<String> chunks) { // Done on the event thread Iterator<String> it = chunks.iterator(); while (it.hasNext()) { output.append(it.next()); } } public String doInBackground() { Process process; try { process = builder.start(); InputStream res = process.getInputStream(); byte[] buffer = new byte[100]; int len; while ( (len=res.read(buffer,0,buffer.length))!=-1) { publish(new String(buffer,0,len)); if (isCancelled()) { process.destroy(); return ""; } } } catch (Exception e) { e.printStackTrace(); } return ""; // Don't care } protected void done() { // Done on the swing event thread output.append("\nALL DONE"); } }
