1. /*
  2. * Copyright 2000,2002-2004 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. package org.apache.tools.ant.taskdefs.optional.net;
  18. import org.apache.commons.net.telnet.TelnetClient;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.io.OutputStream;
  22. import java.util.Calendar;
  23. import java.util.Enumeration;
  24. import java.util.Vector;
  25. import org.apache.tools.ant.BuildException;
  26. import org.apache.tools.ant.Project;
  27. import org.apache.tools.ant.Task;
  28. /**
  29. * Automates the telnet protocol.
  30. *
  31. * @version $Revision: 1.20.2.6 $
  32. */
  33. public class TelnetTask extends Task {
  34. /**
  35. * The userid to login with, if automated login is used
  36. */
  37. private String userid = null;
  38. /**
  39. * The password to login with, if automated login is used
  40. */
  41. private String password = null;
  42. /**
  43. * The server to connect to.
  44. */
  45. private String server = null;
  46. /**
  47. * The tcp port to connect to.
  48. */
  49. private int port = 23;
  50. /**
  51. * The list of read/write commands for this session
  52. */
  53. private Vector telnetTasks = new Vector();
  54. /**
  55. * If true, adds a CR to beginning of login script
  56. */
  57. private boolean addCarriageReturn = false;
  58. /**
  59. * Default time allowed for waiting for a valid response
  60. * for all child reads. A value of 0 means no limit.
  61. */
  62. private Integer defaultTimeout = null;
  63. /**
  64. * Verify that all parameters are included.
  65. * Connect and possibly login
  66. * Iterate through the list of Reads and writes
  67. */
  68. public void execute() throws BuildException {
  69. /** A server name is required to continue */
  70. if (server == null) {
  71. throw new BuildException("No Server Specified");
  72. }
  73. /** A userid and password must appear together
  74. * if they appear. They are not required.
  75. */
  76. if (userid == null && password != null) {
  77. throw new BuildException("No Userid Specified");
  78. }
  79. if (password == null && userid != null) {
  80. throw new BuildException("No Password Specified");
  81. }
  82. /** Create the telnet client object */
  83. AntTelnetClient telnet = null;
  84. try {
  85. telnet = new AntTelnetClient();
  86. try {
  87. telnet.connect(server, port);
  88. } catch (IOException e) {
  89. throw new BuildException("Can't connect to " + server);
  90. }
  91. /** Login if userid and password were specified */
  92. if (userid != null && password != null) {
  93. login(telnet);
  94. }
  95. /** Process each sub command */
  96. Enumeration tasksToRun = telnetTasks.elements();
  97. while (tasksToRun != null && tasksToRun.hasMoreElements()) {
  98. TelnetSubTask task = (TelnetSubTask) tasksToRun.nextElement();
  99. if (task instanceof TelnetRead && defaultTimeout != null) {
  100. ((TelnetRead) task).setDefaultTimeout(defaultTimeout);
  101. }
  102. task.execute(telnet);
  103. }
  104. } finally {
  105. if (telnet != null) {
  106. try {
  107. telnet.disconnect();
  108. } catch (IOException e) {
  109. throw new BuildException("Error disconnecting from "
  110. + server);
  111. }
  112. }
  113. }
  114. }
  115. /**
  116. * Process a 'typical' login. If it differs, use the read
  117. * and write tasks explicitely
  118. */
  119. private void login(AntTelnetClient telnet) {
  120. if (addCarriageReturn) {
  121. telnet.sendString("\n", true);
  122. }
  123. telnet.waitForString("ogin:");
  124. telnet.sendString(userid, true);
  125. telnet.waitForString("assword:");
  126. telnet.sendString(password, false);
  127. }
  128. /**
  129. * Set the the login id to use on the server;
  130. * required if <tt>password</tt> is set.
  131. */
  132. public void setUserid(String u) { this.userid = u; }
  133. /**
  134. * Set the the login password to use
  135. * required if <tt>userid</tt> is set.
  136. */
  137. public void setPassword(String p) { this.password = p; }
  138. /**
  139. * Set the hostname or address of the remote server.
  140. */
  141. public void setServer(String m) { this.server = m; }
  142. /**
  143. * Set the tcp port to connect to; default is 23.
  144. */
  145. public void setPort(int p) { this.port = p; }
  146. /**
  147. * send a carriage return after connecting; optional, defaults to false.
  148. */
  149. public void setInitialCR(boolean b) {
  150. this.addCarriageReturn = b;
  151. }
  152. /**
  153. * set a default timeout in seconds to wait for a response,
  154. * zero means forever (the default)
  155. */
  156. public void setTimeout(Integer i) {
  157. this.defaultTimeout = i;
  158. }
  159. /**
  160. * A string to wait for from the server.
  161. * A subTask <read> tag was found. Create the object,
  162. * Save it in our list, and return it.
  163. */
  164. public TelnetSubTask createRead() {
  165. TelnetSubTask task = (TelnetSubTask) new TelnetRead();
  166. telnetTasks.addElement(task);
  167. return task;
  168. }
  169. /**
  170. * Add text to send to the server
  171. * A subTask <write> tag was found. Create the object,
  172. * Save it in our list, and return it.
  173. */
  174. public TelnetSubTask createWrite() {
  175. TelnetSubTask task = (TelnetSubTask) new TelnetWrite();
  176. telnetTasks.addElement(task);
  177. return task;
  178. }
  179. /**
  180. * This class is the parent of the Read and Write tasks.
  181. * It handles the common attributes for both.
  182. */
  183. public class TelnetSubTask {
  184. protected String taskString = "";
  185. public void execute(AntTelnetClient telnet)
  186. throws BuildException {
  187. throw new BuildException("Shouldn't be able instantiate a SubTask directly");
  188. }
  189. /**
  190. * the message as nested text
  191. */
  192. public void addText(String s) {
  193. setString(getProject().replaceProperties(s));
  194. }
  195. /**
  196. * the message as an attribute
  197. */
  198. public void setString(String s) {
  199. taskString += s;
  200. }
  201. }
  202. /**
  203. * Sends text to the connected server
  204. */
  205. public class TelnetWrite extends TelnetSubTask {
  206. private boolean echoString = true;
  207. public void execute(AntTelnetClient telnet)
  208. throws BuildException {
  209. telnet.sendString(taskString, echoString);
  210. }
  211. /**
  212. * Whether or not the message should be echoed to the log.
  213. * Defaults to <code>true</code>.
  214. */
  215. public void setEcho(boolean b) {
  216. echoString = b;
  217. }
  218. }
  219. /**
  220. * Reads the output from the connected server
  221. * until the required string is found or we time out.
  222. */
  223. public class TelnetRead extends TelnetSubTask {
  224. private Integer timeout = null;
  225. public void execute(AntTelnetClient telnet)
  226. throws BuildException {
  227. telnet.waitForString(taskString, timeout);
  228. }
  229. /**
  230. * a timeout value that overrides any task wide timeout.
  231. */
  232. public void setTimeout(Integer i) {
  233. this.timeout = i;
  234. }
  235. /**
  236. * Sets the default timeout if none has been set already
  237. * @ant.attribute ignore="true"
  238. */
  239. public void setDefaultTimeout(Integer defaultTimeout) {
  240. if (timeout == null) {
  241. timeout = defaultTimeout;
  242. }
  243. }
  244. }
  245. /**
  246. * This class handles the abstraction of the telnet protocol.
  247. * Currently it is a wrapper around <a
  248. * href="http://jakarta.apache.org/commons/net/index.html">Jakarta
  249. * Commons Net</a>.
  250. */
  251. public class AntTelnetClient extends TelnetClient {
  252. /**
  253. * Read from the telnet session until the string we are
  254. * waiting for is found
  255. * @param s The string to wait on
  256. */
  257. public void waitForString(String s) {
  258. waitForString(s, null);
  259. }
  260. /**
  261. * Read from the telnet session until the string we are
  262. * waiting for is found or the timeout has been reached
  263. * @param s The string to wait on
  264. * @param timeout The maximum number of seconds to wait
  265. */
  266. public void waitForString(String s, Integer timeout) {
  267. InputStream is = this.getInputStream();
  268. try {
  269. StringBuffer sb = new StringBuffer();
  270. if (timeout == null || timeout.intValue() == 0) {
  271. while (sb.toString().indexOf(s) == -1) {
  272. sb.append((char) is.read());
  273. }
  274. } else {
  275. Calendar endTime = Calendar.getInstance();
  276. endTime.add(Calendar.SECOND, timeout.intValue());
  277. while (sb.toString().indexOf(s) == -1) {
  278. while (Calendar.getInstance().before(endTime) &&
  279. is.available() == 0) {
  280. Thread.sleep(250);
  281. }
  282. if (is.available() == 0) {
  283. log("Read before running into timeout: "
  284. + sb.toString(), Project.MSG_DEBUG);
  285. throw new BuildException(
  286. "Response timed-out waiting for \"" + s + '\"',
  287. getLocation());
  288. }
  289. sb.append((char) is.read());
  290. }
  291. }
  292. log(sb.toString(), Project.MSG_INFO);
  293. } catch (BuildException be) {
  294. throw be;
  295. } catch (Exception e) {
  296. throw new BuildException(e, getLocation());
  297. }
  298. }
  299. /**
  300. * Write this string to the telnet session.
  301. * @param echoString Logs string sent
  302. */
  303. public void sendString(String s, boolean echoString) {
  304. OutputStream os = this.getOutputStream();
  305. try {
  306. os.write((s + "\n").getBytes());
  307. if (echoString) {
  308. log(s, Project.MSG_INFO);
  309. }
  310. os.flush();
  311. } catch (Exception e) {
  312. throw new BuildException(e, getLocation());
  313. }
  314. }
  315. }
  316. }