KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > optional > net > RExecTask


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18
19 package org.apache.tools.ant.taskdefs.optional.net;
20
21 import org.apache.commons.net.bsd.RExecClient;
22
23 import java.io.IOException JavaDoc;
24 import java.io.InputStream JavaDoc;
25 import java.io.OutputStream JavaDoc;
26 import java.util.Calendar JavaDoc;
27 import java.util.Enumeration JavaDoc;
28 import java.util.Vector JavaDoc;
29 import org.apache.tools.ant.BuildException;
30 import org.apache.tools.ant.Project;
31 import org.apache.tools.ant.Task;
32
33 /**
34  * Automates the rexec protocol.
35  *
36  * @since Ant 1.6
37  */

38
39 public class RExecTask extends Task {
40     /**
41      * The userid to login with, if automated login is used
42      */

43     private String JavaDoc userid = null;
44
45     /**
46      * The password to login with, if automated login is used
47      */

48     private String JavaDoc password = null;
49
50     /**
51      * The command to execute
52      */

53     private String JavaDoc command = null;
54
55     /**
56      * The server to connect to.
57      */

58     private String JavaDoc server = null;
59
60     /**
61      * The tcp port to connect to.
62      */

63     private int port = RExecClient.DEFAULT_PORT;
64
65     /**
66      * The list of read/write commands for this session
67      */

68     private Vector JavaDoc rexecTasks = new Vector JavaDoc();
69
70     /**
71      * If true, adds a CR to beginning of login script
72      */

73     private boolean addCarriageReturn = false;
74
75     /**
76      * Default time allowed for waiting for a valid response
77      * for all child reads. A value of 0 means no limit.
78      */

79     private Integer JavaDoc defaultTimeout = null;
80
81     /**
82      * This class is the parent of the Read and Write tasks.
83      * It handles the common attributes for both.
84      */

85     public class RExecSubTask {
86         // CheckStyle:VisibilityModifier OFF - bc
87
protected String JavaDoc taskString = "";
88         // CheckStyle:VisibilityModifier ON
89

90         /**
91          * Execute the subtask.
92          * @param rexec the client
93          * @throws BuildException always as it is not allowed to instantiate this object
94          */

95         public void execute(AntRExecClient rexec)
96                 throws BuildException {
97             throw new BuildException("Shouldn't be able instantiate a SubTask directly");
98         }
99
100         /**
101          * the message as nested text
102          * @param s the nested text
103          */

104         public void addText(String JavaDoc s) {
105             setString(getProject().replaceProperties(s));
106         }
107
108         /**
109          * the message as an attribute
110          * @param s a <code>String</code> value
111          */

112         public void setString(String JavaDoc s) {
113            taskString += s;
114         }
115     }
116
117     /**
118      * Sends text to the connected server
119      */

120     public class RExecWrite extends RExecSubTask {
121         private boolean echoString = true;
122         /**
123          * Execute the write exec task.
124          * @param rexec the task to use
125          * @throws BuildException on error
126          */

127         public void execute(AntRExecClient rexec)
128                throws BuildException {
129            rexec.sendString(taskString, echoString);
130         }
131
132         /**
133          * Whether or not the message should be echoed to the log.
134          * Defaults to <code>true</code>.
135          * @param b a <code>boolean</code> value
136          */

137         public void setEcho(boolean b) {
138            echoString = b;
139         }
140     }
141
142     /**
143      * Reads the output from the connected server
144      * until the required string is found or we time out.
145      */

146     public class RExecRead extends RExecSubTask {
147         private Integer JavaDoc timeout = null;
148         /**
149          * Execute the read exec task.
150          * @param rexec the task to use
151          * @throws BuildException on error
152          */

153         public void execute(AntRExecClient rexec)
154                throws BuildException {
155             rexec.waitForString(taskString, timeout);
156         }
157         /**
158          * a timeout value that overrides any task wide timeout.
159          * @param i an <code>Integer</code> value
160          */

161         public void setTimeout(Integer JavaDoc i) {
162            this.timeout = i;
163         }
164
165         /**
166          * Sets the default timeout if none has been set already
167          * @param defaultTimeout an <code>Integer</code> value
168          * @ant.attribute ignore="true"
169          */

170         public void setDefaultTimeout(Integer JavaDoc defaultTimeout) {
171            if (timeout == null) {
172               timeout = defaultTimeout;
173            }
174         }
175     }
176
177     /**
178      * This class handles the abstraction of the rexec protocol.
179      * Currently it is a wrapper around <a
180      * HREF="http://jakarta.apache.org/commons/net/index.html">Jakarta
181      * Commons Net</a>.
182      */

183     public class AntRExecClient extends RExecClient {
184         /**
185          * Read from the rexec session until the string we are
186          * waiting for is found
187          * @param s The string to wait on
188          */

189         public void waitForString(String JavaDoc s) {
190             waitForString(s, null);
191         }
192
193         /**
194          * Read from the rexec session until the string we are
195          * waiting for is found or the timeout has been reached
196          * @param s The string to wait on
197          * @param timeout The maximum number of seconds to wait
198          */

199         public void waitForString(String JavaDoc s, Integer JavaDoc timeout) {
200             InputStream JavaDoc is = this.getInputStream();
201             try {
202                 StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
203                 if (timeout == null || timeout.intValue() == 0) {
204                     while (sb.toString().indexOf(s) == -1) {
205                         sb.append((char) is.read());
206                     }
207                 } else {
208                     Calendar JavaDoc endTime = Calendar.getInstance();
209                     endTime.add(Calendar.SECOND, timeout.intValue());
210                     while (sb.toString().indexOf(s) == -1) {
211                         while (Calendar.getInstance().before(endTime)
212                             && is.available() == 0) {
213                             Thread.sleep(250);
214                         }
215                         if (is.available() == 0) {
216                             throw new BuildException(
217                                 "Response timed-out waiting for \"" + s + '\"',
218                                 getLocation());
219                         }
220                         sb.append((char) is.read());
221                     }
222                 }
223                 log(sb.toString(), Project.MSG_INFO);
224             } catch (BuildException be) {
225                 throw be;
226             } catch (Exception JavaDoc e) {
227                 throw new BuildException(e, getLocation());
228             }
229         }
230
231         /**
232          * Write this string to the rexec session.
233          * @param s the string to write
234          * @param echoString if true log the string sent
235          */

236         public void sendString(String JavaDoc s, boolean echoString) {
237             OutputStream JavaDoc os = this.getOutputStream();
238             try {
239                 os.write((s + "\n").getBytes());
240                 if (echoString) {
241                     log(s, Project.MSG_INFO);
242                 }
243                 os.flush();
244             } catch (Exception JavaDoc e) {
245                 throw new BuildException(e, getLocation());
246             }
247         }
248         /**
249          * Read from the rexec session until the EOF is found or
250          * the timeout has been reached
251          * @param timeout The maximum number of seconds to wait
252          */

253         public void waitForEOF(Integer JavaDoc timeout) {
254             InputStream JavaDoc is = this.getInputStream();
255             try {
256                 StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
257                 if (timeout == null || timeout.intValue() == 0) {
258                 int read;
259                     while ((read = is.read()) != -1) {
260                         char c = (char) read;
261                         sb.append(c);
262                         if (c == '\n') {
263                         log(sb.toString(), Project.MSG_INFO);
264                         sb.delete(0, sb.length());
265                         }
266                     }
267                 } else {
268                     Calendar JavaDoc endTime = Calendar.getInstance();
269                     endTime.add(Calendar.SECOND, timeout.intValue());
270                 int read = 0;
271                     while (read != -1) {
272                         while (Calendar.getInstance().before(endTime) && is.available() == 0) {
273                             Thread.sleep(250);
274                         }
275                         if (is.available() == 0) {
276                         log(sb.toString(), Project.MSG_INFO);
277                             throw new BuildException(
278                                                      "Response timed-out waiting for EOF",
279                                                      getLocation());
280                         }
281                         read = is.read();
282                         if (read != -1) {
283                         char c = (char) read;
284                         sb.append(c);
285                         if (c == '\n') {
286                                 log(sb.toString(), Project.MSG_INFO);
287                                 sb.delete(0, sb.length());
288                         }
289                         }
290                     }
291                 }
292                 if (sb.length() > 0) {
293                 log(sb.toString(), Project.MSG_INFO);
294                 }
295             } catch (BuildException be) {
296                 throw be;
297             } catch (Exception JavaDoc e) {
298                 throw new BuildException(e, getLocation());
299             }
300         }
301
302     }
303     /**
304      * A string to wait for from the server.
305      * A subTask &lt;read&gt; tag was found. Create the object,
306      * Save it in our list, and return it.
307      * @return a read sub task
308      */

309
310     public RExecSubTask createRead() {
311         RExecSubTask task = (RExecSubTask) new RExecRead();
312         rexecTasks.addElement(task);
313         return task;
314     }
315     /**
316      * Add text to send to the server
317      * A subTask &lt;write&gt; tag was found. Create the object,
318      * Save it in our list, and return it.
319      * @return a write sub task
320      */

321     public RExecSubTask createWrite() {
322         RExecSubTask task = (RExecSubTask) new RExecWrite();
323         rexecTasks.addElement(task);
324         return task;
325     }
326     /**
327      * Verify that all parameters are included.
328      * Connect and possibly login.
329      * Iterate through the list of Reads and writes.
330      * @throws BuildException on error
331      */

332     public void execute() throws BuildException {
333         /** A server name is required to continue */
334         if (server == null) {
335             throw new BuildException("No Server Specified");
336         }
337         /** A userid and password must appear together
338          * if they appear. They are not required.
339          */

340         if (userid == null && password != null) {
341             throw new BuildException("No Userid Specified");
342         }
343         if (password == null && userid != null) {
344             throw new BuildException("No Password Specified");
345         }
346
347         /** Create the telnet client object */
348         AntRExecClient rexec = null;
349         try {
350             rexec = new AntRExecClient();
351             try {
352                 rexec.connect(server, port);
353             } catch (IOException JavaDoc e) {
354                 throw new BuildException("Can't connect to " + server);
355             }
356             if (userid != null && password != null && command != null
357                 && rexecTasks.size() == 0) {
358                 // simple one-shot execution
359
rexec.rexec(userid, password, command);
360             } else {
361                 // need nested read/write elements
362
handleMultipleTasks(rexec);
363             }
364
365             /** Keep reading input stream until end of it or time-out */
366             rexec.waitForEOF(defaultTimeout);
367         } catch (IOException JavaDoc e) {
368             throw new BuildException("Error r-executing command", e);
369         } finally {
370             if (rexec != null && rexec.isConnected()) {
371                 try {
372                     rexec.disconnect();
373                 } catch (IOException JavaDoc e) {
374                     throw new BuildException("Error disconnecting from "
375                                              + server);
376                 }
377             }
378         }
379     }
380     /**
381      * Process a 'typical' login. If it differs, use the read
382      * and write tasks explicitely
383      */

384     private void login(AntRExecClient rexec) {
385         if (addCarriageReturn) {
386             rexec.sendString("\n", true);
387         }
388         rexec.waitForString("ogin:");
389         rexec.sendString(userid, true);
390         rexec.waitForString("assword:");
391         rexec.sendString(password, false);
392     }
393     /**
394      * Set the the comand to execute on the server;
395      * @param c a <code>String</code> value
396      */

397     public void setCommand(String JavaDoc c) {
398         this.command = c;
399     }
400
401     /**
402      * send a carriage return after connecting; optional, defaults to false.
403      * @param b a <code>boolean</code> value
404      */

405     public void setInitialCR(boolean b) {
406         this.addCarriageReturn = b;
407     }
408     /**
409      * Set the the login password to use
410      * required if <tt>userid</tt> is set.
411      * @param p a <code>String</code> value
412      */

413     public void setPassword(String JavaDoc p) {
414         this.password = p;
415     }
416
417     /**
418      * Set the tcp port to connect to; default is 23.
419      * @param p an <code>int</code> value
420      */

421     public void setPort(int p) {
422         this.port = p;
423     }
424
425     /**
426      * Set the hostname or address of the remote server.
427      * @param m a <code>String</code> value
428      */

429     public void setServer(String JavaDoc m) {
430         this.server = m;
431     }
432
433     /**
434      * set a default timeout in seconds to wait for a response,
435      * zero means forever (the default)
436      * @param i an <code>Integer</code> value
437      */

438     public void setTimeout(Integer JavaDoc i) {
439         this.defaultTimeout = i;
440     }
441     /**
442      * Set the the login id to use on the server;
443      * required if <tt>password</tt> is set.
444      * @param u a <code>String</code> value
445      */

446     public void setUserid(String JavaDoc u) {
447         this.userid = u;
448     }
449
450     /**
451      * Deals with multiple read/write calls.
452      *
453      * @since Ant 1.6.3
454      */

455     private void handleMultipleTasks(AntRExecClient rexec) {
456
457         /** Login if userid and password were specified */
458         if (userid != null && password != null) {
459             login(rexec);
460         }
461         /** Process each sub command */
462         Enumeration JavaDoc tasksToRun = rexecTasks.elements();
463         while (tasksToRun != null && tasksToRun.hasMoreElements()) {
464             RExecSubTask task = (RExecSubTask) tasksToRun.nextElement();
465             if (task instanceof RExecRead && defaultTimeout != null) {
466                 ((RExecRead) task).setDefaultTimeout(defaultTimeout);
467             }
468             task.execute(rexec);
469         }
470     }
471 }
472
Popular Tags