source: other-projects/trunk/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHExec.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 8.5 KB
Line 
1/*
2 * Copyright 2003-2005 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18package org.apache.tools.ant.taskdefs.optional.ssh;
19
20import org.apache.tools.ant.BuildException;
21import org.apache.tools.ant.Project;
22import org.apache.tools.ant.util.TeeOutputStream;
23
24import java.io.ByteArrayOutputStream;
25import java.io.File;
26import java.io.FileWriter;
27import java.io.IOException;
28import java.io.StringReader;
29
30import com.jcraft.jsch.ChannelExec;
31import com.jcraft.jsch.JSchException;
32import com.jcraft.jsch.Session;
33
34/**
35 * Executes a command on a remote machine via ssh.
36 *
37 * @created February 2, 2003
38 * @since Ant 1.6
39 */
40public class SSHExec extends SSHBase {
41
42 private static final int BUFFER_SIZE = 1024;
43
44 /** the command to execute via ssh */
45 private String command = null;
46
47 /** units are milliseconds, default is 0=infinite */
48 private long maxwait = 0;
49
50 /** for waiting for the command to finish */
51 private Thread thread = null;
52
53 private String outputProperty = null; // like <exec>
54 private File outputFile = null; // like <exec>
55 private boolean append = false; // like <exec>
56
57 private static final String TIMEOUT_MESSAGE =
58 "Timeout period exceeded, connection dropped.";
59
60 /**
61 * Constructor for SSHExecTask.
62 */
63 public SSHExec() {
64 super();
65 }
66
67 /**
68 * Sets the command to execute on the remote host.
69 *
70 * @param command The new command value
71 */
72 public void setCommand(String command) {
73 this.command = command;
74 }
75
76 /**
77 * The connection can be dropped after a specified number of
78 * milliseconds. This is sometimes useful when a connection may be
79 * flaky. Default is 0, which means &quot;wait forever&quot;.
80 *
81 * @param timeout The new timeout value in seconds
82 */
83 public void setTimeout(long timeout) {
84 maxwait = timeout;
85 }
86
87 /**
88 * If used, stores the output of the command to the given file.
89 *
90 * @param output The file to write to.
91 */
92 public void setOutput(File output) {
93 outputFile = output;
94 }
95
96 /**
97 * Determines if the output is appended to the file given in
98 * <code>setOutput</code>. Default is false, that is, overwrite
99 * the file.
100 *
101 * @param append True to append to an existing file, false to overwrite.
102 */
103 public void setAppend(boolean append) {
104 this.append = append;
105 }
106
107 /**
108 * If set, the output of the command will be stored in the given property.
109 *
110 * @param property The name of the property in which the command output
111 * will be stored.
112 */
113 public void setOutputproperty(String property) {
114 outputProperty = property;
115 }
116
117 /**
118 * Execute the command on the remote host.
119 *
120 * @exception BuildException Most likely a network error or bad parameter.
121 */
122 public void execute() throws BuildException {
123 if (getHost() == null) {
124 throw new BuildException("Host is required.");
125 }
126 if (getUserInfo().getName() == null) {
127 throw new BuildException("Username is required.");
128 }
129 if (getUserInfo().getKeyfile() == null
130 && getUserInfo().getPassword() == null) {
131 throw new BuildException("Password or Keyfile is required.");
132 }
133 if (command == null) {
134 throw new BuildException("Command is required.");
135 }
136
137 ByteArrayOutputStream out = new ByteArrayOutputStream();
138 TeeOutputStream tee = new TeeOutputStream(out, System.out);
139
140 Session session = null;
141 try {
142 // execute the command
143 session = openSession();
144 session.setTimeout((int) maxwait);
145 final ChannelExec channel = (ChannelExec) session.openChannel("exec");
146 channel.setCommand(command);
147 channel.setOutputStream(tee);
148 channel.setExtOutputStream(tee);
149 channel.connect();
150
151 // wait for it to finish
152 thread =
153 new Thread() {
154 public void run() {
155 while (!channel.isEOF()) {
156 if (thread == null) {
157 return;
158 }
159 try {
160 sleep(500);
161 } catch (Exception e) {
162 // ignored
163 }
164 }
165 }
166 };
167
168 thread.start();
169 thread.join(maxwait);
170
171 if (thread.isAlive()) {
172 // ran out of time
173 thread = null;
174 if (getFailonerror()) {
175 throw new BuildException(TIMEOUT_MESSAGE);
176 } else {
177 log(TIMEOUT_MESSAGE, Project.MSG_ERR);
178 }
179 } else {
180 // completed successfully
181 if (outputProperty != null) {
182 getProject().setProperty(outputProperty, out.toString());
183 }
184 if (outputFile != null) {
185 writeToFile(out.toString(), append, outputFile);
186 }
187
188 // this is the wrong test if the remote OS is OpenVMS,
189 // but there doesn't seem to be a way to detect it.
190 int ec = channel.getExitStatus();
191 if (ec != 0) {
192 String msg = "Remote command failed with exit status " + ec;
193 if (getFailonerror()) {
194 throw new BuildException(msg);
195 } else {
196 log(msg, Project.MSG_ERR);
197 }
198 }
199 }
200 } catch (BuildException e) {
201 throw e;
202 } catch (JSchException e) {
203 if (e.getMessage().indexOf("session is down") >= 0) {
204 if (getFailonerror()) {
205 throw new BuildException(TIMEOUT_MESSAGE, e);
206 } else {
207 log(TIMEOUT_MESSAGE, Project.MSG_ERR);
208 }
209 } else {
210 if (getFailonerror()) {
211 throw new BuildException(e);
212 } else {
213 log("Caught exception: " + e.getMessage(),
214 Project.MSG_ERR);
215 }
216 }
217 } catch (Exception e) {
218 if (getFailonerror()) {
219 throw new BuildException(e);
220 } else {
221 log("Caught exception: " + e.getMessage(), Project.MSG_ERR);
222 }
223 } finally {
224 if (session != null && session.isConnected()) {
225 session.disconnect();
226 }
227 }
228 }
229
230
231 /**
232 * Writes a string to a file. If destination file exists, it may be
233 * overwritten depending on the "append" value.
234 *
235 * @param from string to write
236 * @param to file to write to
237 * @param append if true, append to existing file, else overwrite
238 * @exception Exception most likely an IOException
239 */
240 private void writeToFile(String from, boolean append, File to)
241 throws IOException {
242 FileWriter out = null;
243 try {
244 out = new FileWriter(to.getAbsolutePath(), append);
245 StringReader in = new StringReader(from);
246 char[] buffer = new char[8192];
247 int bytesRead;
248 while (true) {
249 bytesRead = in.read(buffer);
250 if (bytesRead == -1) {
251 break;
252 }
253 out.write(buffer, 0, bytesRead);
254 }
255 out.flush();
256 } finally {
257 if (out != null) {
258 out.close();
259 }
260 }
261 }
262
263}
264
Note: See TracBrowser for help on using the repository browser.