| /* |
| * Copyright (c) 1998, 1999, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.tools.example.debug.bdi; |
| |
| import com.sun.jdi.*; |
| import com.sun.jdi.connect.LaunchingConnector; |
| import com.sun.jdi.connect.Connector; |
| import com.sun.jdi.connect.VMStartException; |
| import com.sun.jdi.connect.IllegalConnectorArgumentsException; |
| import java.io.*; |
| import java.util.Map; |
| import javax.swing.SwingUtilities; |
| |
| |
| class ChildSession extends Session { |
| |
| private Process process; |
| |
| private PrintWriter in; |
| private BufferedReader out; |
| private BufferedReader err; |
| |
| private InputWriter inputWriter; |
| private OutputReader outputReader; |
| private OutputReader errorReader; |
| |
| private InputListener input; |
| private OutputListener output; |
| private OutputListener error; |
| |
| public ChildSession(ExecutionManager runtime, |
| String userVMArgs, String cmdLine, |
| InputListener input, |
| OutputListener output, |
| OutputListener error, |
| OutputListener diagnostics) { |
| this(runtime, getVM(diagnostics, userVMArgs, cmdLine), |
| input, output, error, diagnostics); |
| } |
| |
| public ChildSession(ExecutionManager runtime, |
| LaunchingConnector connector, |
| Map<String, Connector.Argument> arguments, |
| InputListener input, |
| OutputListener output, |
| OutputListener error, |
| OutputListener diagnostics) { |
| this(runtime, generalGetVM(diagnostics, connector, arguments), |
| input, output, error, diagnostics); |
| } |
| |
| private ChildSession(ExecutionManager runtime, |
| VirtualMachine vm, |
| InputListener input, |
| OutputListener output, |
| OutputListener error, |
| OutputListener diagnostics) { |
| super(vm, runtime, diagnostics); |
| this.input = input; |
| this.output = output; |
| this.error = error; |
| } |
| |
| public boolean attach() { |
| |
| if (!connectToVMProcess()) { |
| diagnostics.putString("Could not launch VM"); |
| return false; |
| } |
| |
| /* |
| * Create a Thread that will retrieve and display any output. |
| * Needs to be high priority, else debugger may exit before |
| * it can be displayed. |
| */ |
| |
| //### Rename InputWriter and OutputReader classes |
| //### Thread priorities cribbed from ttydebug. Think about them. |
| |
| OutputReader outputReader = |
| new OutputReader("output reader", "output", |
| out, output, diagnostics); |
| outputReader.setPriority(Thread.MAX_PRIORITY-1); |
| outputReader.start(); |
| |
| OutputReader errorReader = |
| new OutputReader("error reader", "error", |
| err, error, diagnostics); |
| errorReader.setPriority(Thread.MAX_PRIORITY-1); |
| errorReader.start(); |
| |
| InputWriter inputWriter = |
| new InputWriter("input writer", in, input); |
| inputWriter.setPriority(Thread.MAX_PRIORITY-1); |
| inputWriter.start(); |
| |
| if (!super.attach()) { |
| if (process != null) { |
| process.destroy(); |
| process = null; |
| } |
| return false; |
| } |
| |
| //### debug |
| //System.out.println("IO after attach: "+ inputWriter + " " + outputReader + " "+ errorReader); |
| |
| return true; |
| } |
| |
| public void detach() { |
| |
| //### debug |
| //System.out.println("IO before detach: "+ inputWriter + " " + outputReader + " "+ errorReader); |
| |
| super.detach(); |
| |
| /* |
| inputWriter.quit(); |
| outputReader.quit(); |
| errorReader.quit(); |
| */ |
| |
| if (process != null) { |
| process.destroy(); |
| process = null; |
| } |
| |
| } |
| |
| /** |
| * Launch child java interpreter, return host:port |
| */ |
| |
| static private void dumpStream(OutputListener diagnostics, |
| InputStream stream) throws IOException { |
| BufferedReader in = |
| new BufferedReader(new InputStreamReader(stream)); |
| String line; |
| while ((line = in.readLine()) != null) { |
| diagnostics.putString(line); |
| } |
| } |
| |
| static private void dumpFailedLaunchInfo(OutputListener diagnostics, |
| Process process) { |
| try { |
| dumpStream(diagnostics, process.getErrorStream()); |
| dumpStream(diagnostics, process.getInputStream()); |
| } catch (IOException e) { |
| diagnostics.putString("Unable to display process output: " + |
| e.getMessage()); |
| } |
| } |
| |
| static private VirtualMachine getVM(OutputListener diagnostics, |
| String userVMArgs, |
| String cmdLine) { |
| VirtualMachineManager manager = Bootstrap.virtualMachineManager(); |
| LaunchingConnector connector = manager.defaultConnector(); |
| Map<String, Connector.Argument> arguments = connector.defaultArguments(); |
| arguments.get("options").setValue(userVMArgs); |
| arguments.get("main").setValue(cmdLine); |
| return generalGetVM(diagnostics, connector, arguments); |
| } |
| |
| static private VirtualMachine generalGetVM(OutputListener diagnostics, |
| LaunchingConnector connector, |
| Map<String, Connector.Argument> arguments) { |
| VirtualMachine vm = null; |
| try { |
| diagnostics.putString("Starting child."); |
| vm = connector.launch(arguments); |
| } catch (IOException ioe) { |
| diagnostics.putString("Unable to start child: " + ioe.getMessage()); |
| } catch (IllegalConnectorArgumentsException icae) { |
| diagnostics.putString("Unable to start child: " + icae.getMessage()); |
| } catch (VMStartException vmse) { |
| diagnostics.putString("Unable to start child: " + vmse.getMessage() + '\n'); |
| dumpFailedLaunchInfo(diagnostics, vmse.process()); |
| } |
| return vm; |
| } |
| |
| private boolean connectToVMProcess() { |
| if (vm == null) { |
| return false; |
| } |
| process = vm.process(); |
| in = new PrintWriter(new OutputStreamWriter(process.getOutputStream())); |
| //### Note small buffer sizes! |
| out = new BufferedReader(new InputStreamReader(process.getInputStream()), 1); |
| err = new BufferedReader(new InputStreamReader(process.getErrorStream()), 1); |
| return true; |
| } |
| |
| /** |
| * Threads to handle application input/output. |
| */ |
| |
| private static class OutputReader extends Thread { |
| |
| private String streamName; |
| private BufferedReader stream; |
| private OutputListener output; |
| private OutputListener diagnostics; |
| private boolean running = true; |
| private char[] buffer = new char[512]; |
| |
| OutputReader(String threadName, |
| String streamName, |
| BufferedReader stream, |
| OutputListener output, |
| OutputListener diagnostics) { |
| super(threadName); |
| this.streamName = streamName; |
| this.stream = stream; |
| this.output = output; |
| this.diagnostics = diagnostics; |
| } |
| |
| public void quit() { |
| running = false; |
| } |
| |
| public void run() { |
| try { |
| int count; |
| while (running && (count = stream.read(buffer, 0, 512)) != -1) { |
| if (count > 0) { |
| // Run in Swing event dispatcher thread. |
| final String chars = new String(buffer, 0, count); |
| SwingUtilities.invokeLater(new Runnable() { |
| public void run() { |
| output.putString(chars); |
| } |
| }); |
| } |
| //### Should we sleep briefly here? |
| } |
| } catch (IOException e) { |
| // Run in Swing event dispatcher thread. |
| SwingUtilities.invokeLater(new Runnable() { |
| public void run() { |
| diagnostics.putString("IO error reading " + |
| streamName + |
| " stream of child java interpreter"); |
| } |
| }); |
| } |
| } |
| } |
| |
| private static class InputWriter extends Thread { |
| |
| private PrintWriter stream; |
| private InputListener input; |
| private boolean running = true; |
| |
| InputWriter(String threadName, |
| PrintWriter stream, |
| InputListener input) { |
| super(threadName); |
| this.stream = stream; |
| this.input = input; |
| } |
| |
| public void quit() { |
| //### Won't have much effect if blocked on input! |
| running = false; |
| } |
| |
| public void run() { |
| String line; |
| while (running) { |
| line = input.getLine(); |
| stream.println(line); |
| // Should not be needed for println above! |
| stream.flush(); |
| } |
| } |
| } |
| |
| } |