273 lines · 9.4 KB · Java
RawDownload
/* * Copyright (c) 1999, 2008, 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.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] = 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;        }    }}