1 /*
   2  * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * A Launcher to launch a java process with its standard input, output,
  26  * and error streams connected to a socket.
  27  */
  28 import java.net.*;
  29 import java.nio.channels.*;
  30 import java.io.IOException;
  31 
  32 public class Launcher {
  33 
  34     static {
  35         System.loadLibrary("Launcher");
  36     }
  37 
  38     private static native void launch0(String cmdarray[], int fd) throws IOException;
  39 
  40     private static void launch(String className, String options[], String args[], int fd) throws IOException {
  41         // java [-options] class [args...]
  42         int optsLen = (options == null) ? 0 : options.length;
  43         int argsLen = (args == null) ? 0 : args.length;
  44         int len = 1 + optsLen + 1 + argsLen;
  45         String cmdarray[] = new String[len];
  46         int pos = 0;
  47         cmdarray[pos++] = Util.javaCommand();
  48         if (options != null) {
  49             for (String opt: options) {
  50                 cmdarray[pos++] = opt;
  51             }
  52         }
  53         cmdarray[pos++] = className;
  54         if (args != null) {
  55             for (String arg: args) {
  56                 cmdarray[pos++] = arg;
  57             }
  58         }
  59         launch0(cmdarray, fd);
  60     }
  61 
  62     /*
  63      * Launch 'java' with specified class with the specified arguments (may be null).
  64      * The launched process will inherit a connected TCP socket. The remote endpoint
  65      * will be the SocketChannel returned by this method.
  66      */
  67     public static SocketChannel launchWithSocketChannel(String className, String options[], String args[]) throws IOException {
  68         ServerSocketChannel ssc = ServerSocketChannel.open();
  69         ssc.socket().bind(new InetSocketAddress(0));
  70         InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(),
  71                                                       ssc.socket().getLocalPort());
  72         SocketChannel sc1 = SocketChannel.open(isa);
  73         SocketChannel sc2 = ssc.accept();
  74         launch(className, options, args, Util.getFD(sc2));
  75         sc2.close();
  76         ssc.close();
  77         return sc1;
  78     }
  79 
  80     public static SocketChannel launchWithSocketChannel(String className, String args[]) throws IOException {
  81         return launchWithSocketChannel(className, null, args);
  82     }
  83 
  84     public static SocketChannel launchWithSocketChannel(String className) throws IOException {
  85         return launchWithSocketChannel(className, null);
  86     }
  87 
  88     /*
  89      * Launch 'java' with specified class with the specified arguments (may be null).
  90      * The launched process will inherited a TCP listener socket.
  91      * Once launched this method tries to connect to service. If a connection
  92      * can be established a SocketChannel, connected to the service, is returned.
  93      */
  94     public static SocketChannel launchWithServerSocketChannel(String className, String options[], String args[])
  95         throws IOException
  96     {
  97         ServerSocketChannel ssc = ServerSocketChannel.open();
  98         ssc.socket().bind(new InetSocketAddress(0));
  99         int port = ssc.socket().getLocalPort();
 100         launch(className, options, args, Util.getFD(ssc));
 101         ssc.close();
 102         InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(), port);
 103         return SocketChannel.open(isa);
 104     }
 105 
 106     public static SocketChannel launchWithServerSocketChannel(String className, String args[]) throws IOException {
 107         return launchWithServerSocketChannel(className, null, args);
 108     }
 109 
 110     public static SocketChannel launchWithServerSocketChannel(String className) throws IOException {
 111         return launchWithServerSocketChannel(className, null);
 112     }
 113 
 114     /*
 115      * Launch 'java' with specified class with the specified arguments (may be null).
 116      * The launch process will inherited a bound UDP socket.
 117      * Once launched this method creates a DatagramChannel and "connects
 118      * it to the service. The created DatagramChannel is then returned.
 119      * As it is connected any packets sent from the socket will be
 120      * sent to the service.
 121      */
 122     public static DatagramChannel launchWithDatagramChannel(String className, String options[], String args[])
 123         throws IOException
 124     {
 125         DatagramChannel dc = DatagramChannel.open();
 126         dc.socket().bind(new InetSocketAddress(0));
 127 
 128         int port = dc.socket().getLocalPort();
 129         launch(className, options, args, Util.getFD(dc));
 130         dc.close();
 131 
 132         dc = DatagramChannel.open();
 133         InetAddress address = InetAddress.getLocalHost();
 134         if (address.isLoopbackAddress()) {
 135             address = InetAddress.getLoopbackAddress();
 136         }
 137         InetSocketAddress isa = new InetSocketAddress(address, port);
 138 
 139         dc.connect(isa);
 140         return dc;
 141     }
 142 
 143     public static DatagramChannel launchWithDatagramChannel(String className, String args[]) throws IOException {
 144         return launchWithDatagramChannel(className, null, args);
 145     }
 146 
 147     public static DatagramChannel launchWithDatagramChannel(String className) throws IOException {
 148         return launchWithDatagramChannel(className, null);
 149     }
 150 }