--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/tools/jdi/AbstractLauncher.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,273 @@
+/*
+ * Copyright 1999-2004 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.jdi;
+
+import com.sun.tools.jdi.*;
+import com.sun.jdi.connect.*;
+import com.sun.jdi.connect.spi.*;
+import com.sun.jdi.*;
+
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.List;
+import java.util.ArrayList;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+
+abstract class AbstractLauncher extends ConnectorImpl implements LaunchingConnector {
+
+ abstract public VirtualMachine
+ launch(Map<String,? extends Connector.Argument> arguments)
+ throws IOException,
+ IllegalConnectorArgumentsException,
+ VMStartException;
+ abstract public String name();
+ abstract public String description();
+
+ ThreadGroup grp;
+
+ AbstractLauncher() {
+ super();
+
+ grp = Thread.currentThread().getThreadGroup();
+ ThreadGroup parent = null;
+ while ((parent = grp.getParent()) != null) {
+ grp = parent;
+ }
+ }
+
+ String[] tokenizeCommand(String command, char quote) {
+ String quoteStr = String.valueOf(quote); // easier to deal with
+
+ /*
+ * Tokenize the command, respecting the given quote character.
+ */
+ StringTokenizer tokenizer = new StringTokenizer(command,
+ quote + " \t\r\n\f",
+ true);
+ String quoted = null;
+ String pending = null;
+ List<String> tokenList = new ArrayList<String>();
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ if (quoted != null) {
+ if (token.equals(quoteStr)) {
+ tokenList.add(quoted);
+ quoted = null;
+ } else {
+ quoted += token;
+ }
+ } else if (pending != null) {
+ if (token.equals(quoteStr)) {
+ quoted = pending;
+ } else if ((token.length() == 1) &&
+ Character.isWhitespace(token.charAt(0))) {
+ tokenList.add(pending);
+ } else {
+ throw new InternalException("Unexpected token: " + token);
+ }
+ pending = null;
+ } else {
+ if (token.equals(quoteStr)) {
+ quoted = "";
+ } else if ((token.length() == 1) &&
+ Character.isWhitespace(token.charAt(0))) {
+ // continue
+ } else {
+ pending = token;
+ }
+ }
+ }
+
+ /*
+ * Add final token.
+ */
+ if (pending != null) {
+ tokenList.add(pending);
+ }
+
+ /*
+ * An unclosed quote at the end of the command. Do an
+ * implicit end quote.
+ */
+ if (quoted != null) {
+ tokenList.add(quoted);
+ }
+
+ String[] tokenArray = new String[tokenList.size()];
+ for (int i = 0; i < tokenList.size(); i++) {
+ tokenArray[i] = (String)tokenList.get(i);
+ }
+ return tokenArray;
+ }
+
+ protected VirtualMachine launch(String[] commandArray, String address,
+ TransportService.ListenKey listenKey,
+ TransportService ts)
+ throws IOException, VMStartException {
+ Helper helper = new Helper(commandArray, address, listenKey, ts);
+ helper.launchAndAccept();
+
+ VirtualMachineManager manager =
+ Bootstrap.virtualMachineManager();
+
+ return manager.createVirtualMachine(helper.connection(),
+ helper.process());
+ }
+
+ /**
+ * This class simply provides a context for a single launch and
+ * accept. It provides instance fields that can be used by
+ * all threads involved. This stuff can't be in the Connector proper
+ * because the connector is is a singleton and not specific to any
+ * one launch.
+ */
+ private class Helper {
+ private final String address;
+ private TransportService.ListenKey listenKey;
+ private TransportService ts;
+ private final String[] commandArray;
+ private Process process = null;
+ private Connection connection = null;
+ private IOException acceptException = null;
+ private boolean exited = false;
+
+ Helper(String[] commandArray, String address, TransportService.ListenKey listenKey,
+ TransportService ts) {
+ this.commandArray = commandArray;
+ this.address = address;
+ this.listenKey = listenKey;
+ this.ts = ts;
+ }
+
+ String commandString() {
+ String str = "";
+ for (int i = 0; i < commandArray.length; i++) {
+ if (i > 0) {
+ str += " ";
+ }
+ str += commandArray[i];
+ }
+ return str;
+ }
+
+ synchronized void launchAndAccept() throws
+ IOException, VMStartException {
+
+ process = Runtime.getRuntime().exec(commandArray);
+
+ Thread acceptingThread = acceptConnection();
+ Thread monitoringThread = monitorTarget();
+ try {
+ while ((connection == null) &&
+ (acceptException == null) &&
+ !exited) {
+ wait();
+ }
+
+ if (exited) {
+ throw new VMStartException(
+ "VM initialization failed for: " + commandString(), process);
+ }
+ if (acceptException != null) {
+ // Rethrow the exception in this thread
+ throw acceptException;
+ }
+ } catch (InterruptedException e) {
+ throw new InterruptedIOException("Interrupted during accept");
+ } finally {
+ acceptingThread.interrupt();
+ monitoringThread.interrupt();
+ }
+ }
+
+ Process process() {
+ return process;
+ }
+
+ Connection connection() {
+ return connection;
+ }
+
+ synchronized void notifyOfExit() {
+ exited = true;
+ notify();
+ }
+
+ synchronized void notifyOfConnection(Connection connection) {
+ this.connection = connection;
+ notify();
+ }
+
+ synchronized void notifyOfAcceptException(IOException acceptException) {
+ this.acceptException = acceptException;
+ notify();
+ }
+
+ Thread monitorTarget() {
+ Thread thread = new Thread(grp,
+ "launched target monitor") {
+ public void run() {
+ try {
+ process.waitFor();
+ /*
+ * Notify waiting thread of VM error termination
+ */
+ notifyOfExit();
+ } catch (InterruptedException e) {
+ // Connection has been established, stop monitoring
+ }
+ }
+ };
+ thread.setDaemon(true);
+ thread.start();
+ return thread;
+ }
+
+ Thread acceptConnection() {
+ Thread thread = new Thread(grp,
+ "connection acceptor") {
+ public void run() {
+ try {
+ Connection connection = ts.accept(listenKey, 0, 0);
+ /*
+ * Notify waiting thread of connection
+ */
+ notifyOfConnection(connection);
+ } catch (InterruptedIOException e) {
+ // VM terminated, stop accepting
+ } catch (IOException e) {
+ // Report any other exception to waiting thread
+ notifyOfAcceptException(e);
+ }
+ }
+ };
+ thread.setDaemon(true);
+ thread.start();
+ return thread;
+ }
+ }
+}