File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\slaves\Channels.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 package hudson.slaves;
25
26 import hudson.Launcher.LocalLauncher;
27 import hudson.Proc;
28 import hudson.FilePath;
29 import hudson.model.Computer;
30 import hudson.model.TaskListener;
31 import hudson.remoting.Channel;
32 import hudson.remoting.Launcher;
33 import hudson.remoting.SocketInputStream;
34 import hudson.remoting.SocketOutputStream;
35 import hudson.util.ClasspathBuilder;
36 import hudson.util.JVMBuilder;
37 import hudson.util.StreamCopyThread;
38
39 import java.io.BufferedInputStream;
40 import java.io.BufferedOutputStream;
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.io.OutputStream;
44 import java.net.InetSocketAddress;
45 import java.net.ServerSocket;
46 import java.net.Socket;
47 import java.util.Map;
48 import java.util.concurrent.ExecutorService;
49 import java.util.logging.Level;
50 import java.util.logging.Logger;
51
52 /**
53 * Various convenient subtype of {@link Channel}s.
54 *
55 * @author Kohsuke Kawaguchi
56 */
57 public class Channels {
58 /**
59 * @deprecated since 2009-04-13.
60 * Use {@link #forProcess(String, ExecutorService, InputStream, OutputStream, OutputStream, Proc)}
61 */
62 public static Channel forProcess(String name, ExecutorService execService, InputStream in, OutputStream out, Proc proc) throws IOException {
63 return forProcess(name,execService,in,out,null,proc);
64 }
65
66 /**
67 * Creates a channel that wraps a remote process, so that when we shut down the connection
68 * we kill the process.
69 */
70 public static Channel forProcess(String name, ExecutorService execService, InputStream in, OutputStream out, OutputStream header, final Proc proc) throws IOException {
71 return new Channel(name, execService, in, out, header) {
72 /**
73 * Kill the process when the channel is severed.
74 */
75 @Override
76 protected synchronized void terminate(IOException e) {
77 super.terminate(e);
78 try {
79 proc.kill();
80 } catch (IOException x) {
81 // we are already in the error recovery mode, so just record it and move on
82 LOGGER.log(Level.INFO, "Failed to terminate the severed connection",x);
83 } catch (InterruptedException x) {
84 // process the interrupt later
85 Thread.currentThread().interrupt();
86 }
87 }
88
89 @Override
90 public synchronized void close() throws IOException {
91 super.close();
92 // wait for the child process to complete
93 try {
94 proc.join();
95 } catch (InterruptedException e) {
96 // process the interrupt later
97 Thread.currentThread().interrupt();
98 }
99 }
100 };
101 }
102
103 public static Channel forProcess(String name, ExecutorService execService, final Process proc, OutputStream header) throws IOException {
104 final Thread thread = new StreamCopyThread(name + " stderr", proc.getErrorStream(), header);
105 thread.start();
106
107 return new Channel(name, execService, proc.getInputStream(), proc.getOutputStream(), header) {
108 /**
109 * Kill the process when the channel is severed.
110 */
111 @Override
112 protected synchronized void terminate(IOException e) {
113 super.terminate(e);
114 proc.destroy();
115 // the stderr copier should exit by itself
116 }
117
118 @Override
119 public synchronized void close() throws IOException {
120 super.close();
121 // wait for Maven to complete
122 try {
123 proc.waitFor();
124 thread.join();
125 } catch (InterruptedException e) {
126 // process the interrupt later
127 Thread.currentThread().interrupt();
128 }
129 }
130 };
131 }
132
133 /**
134 * Launches a new JVM with the given classpath and system properties, establish a communication channel,
135 * and return a {@link Channel} to it.
136 *
137 * @param displayName
138 * Human readable name of what this JVM represents. For example "Selenium grid" or "Hadoop".
139 * This token is used for messages to {@code listener}.
140 * @param listener
141 * The progress of the launcher and the failure information will be sent here. Must not be null.
142 * @param workDir
143 * If non-null, the new JVM will have this directory as the working directory. This must be a local path.
144 * @param classpath
145 * The classpath of the new JVM. Can be null if you just need {@code slave.jar} (and everything else
146 * can be sent over the channel.) But if you have jars that are known to be necessary by the new JVM,
147 * setting it here will improve the classloading performance (by avoiding remote class file transfer.)
148 * Classes in this classpath will also take precedence over any other classes that's sent via the channel
149 * later, so it's also useful for making sure you get the version of the classes you want.
150 * @param systemProperties
151 * If the new JVM should have a certain system properties set. Can be null.
152 *
153 * @return
154 * never null
155 * @since 1.300
156 */
157 public static Channel newJVM(String displayName, TaskListener listener, FilePath workDir, ClasspathBuilder classpath, Map<String,String> systemProperties) throws IOException {
158 JVMBuilder vmb = new JVMBuilder();
159 vmb.systemProperties(systemProperties);
160
161 return newJVM(displayName,listener,vmb,workDir,classpath);
162 }
163
164 /**
165 * Launches a new JVM with the given classpath, establish a communication channel,
166 * and return a {@link Channel} to it.
167 *
168 * @param displayName
169 * Human readable name of what this JVM represents. For example "Selenium grid" or "Hadoop".
170 * This token is used for messages to {@code listener}.
171 * @param listener
172 * The progress of the launcher and the failure information will be sent here. Must not be null.
173 * @param workDir
174 * If non-null, the new JVM will have this directory as the working directory. This must be a local path.
175 * @param classpath
176 * The classpath of the new JVM. Can be null if you just need {@code slave.jar} (and everything else
177 * can be sent over the channel.) But if you have jars that are known to be necessary by the new JVM,
178 * setting it here will improve the classloading performance (by avoiding remote class file transfer.)
179 * Classes in this classpath will also take precedence over any other classes that's sent via the channel
180 * later, so it's also useful for making sure you get the version of the classes you want.
181 * @param vmb
182 * A partially configured {@link JVMBuilder} that allows the caller to fine-tune the launch parameter.
183 *
184 * @return
185 * never null
186 * @since 1.361
187 */
188 public static Channel newJVM(String displayName, TaskListener listener, JVMBuilder vmb, FilePath workDir, ClasspathBuilder classpath) throws IOException {
189 ServerSocket serverSocket = new ServerSocket();
190 serverSocket.bind(new InetSocketAddress("localhost",0));
191 serverSocket.setSoTimeout(10*1000);
192
193 // use -cp + FQCN instead of -jar since remoting.jar can be rebundled (like in the case of the swarm plugin.)
194 vmb.classpath().addJarOf(Channel.class);
195 vmb.mainClass(Launcher.class);
196
197 if(classpath!=null)
198 vmb.args().add("-cp").add(classpath);
199 vmb.args().add("-connectTo","localhost:"+serverSocket.getLocalPort());
200
201 listener.getLogger().println("Starting "+displayName);
202 Proc p = vmb.launch(new LocalLauncher(listener)).stdout(listener).pwd(workDir).start();
203
204 Socket s = serverSocket.accept();
205 serverSocket.close();
206
207 return forProcess("Channel to "+displayName, Computer.threadPoolForRemoting,
208 new BufferedInputStream(new SocketInputStream(s)),
209 new BufferedOutputStream(new SocketOutputStream(s)),null,p);
210 }
211
212
213 private static final Logger LOGGER = Logger.getLogger(Channels.class.getName());
214 }
215