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 */
28import java.net.*;
29import java.nio.channels.*;
30import java.io.IOException;
31
32public 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}
151