diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java | 479 |
1 files changed, 479 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java new file mode 100644 index 00000000..01cb4ba9 --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java @@ -0,0 +1,479 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.tools.ant.taskdefs.optional.net; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Calendar; +import java.util.Enumeration; +import java.util.Vector; + +import org.apache.commons.net.bsd.RExecClient; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; + +/** + * Automates the rexec protocol. + * + * @since Ant 1.6 + */ + +public class RExecTask extends Task { + + private static final int PAUSE_TIME = 250; + + /** + * The userid to login with, if automated login is used + */ + private String userid = null; + + /** + * The password to login with, if automated login is used + */ + private String password = null; + + /** + * The command to execute + */ + private String command = null; + + /** + * The server to connect to. + */ + private String server = null; + + /** + * The tcp port to connect to. + */ + private int port = RExecClient.DEFAULT_PORT; + + /** + * The list of read/write commands for this session + */ + private Vector rexecTasks = new Vector(); + + /** + * If true, adds a CR to beginning of login script + */ + private boolean addCarriageReturn = false; + + /** + * Default time allowed for waiting for a valid response + * for all child reads. A value of 0 means no limit. + */ + private Integer defaultTimeout = null; + + /** + * This class is the parent of the Read and Write tasks. + * It handles the common attributes for both. + */ + public class RExecSubTask { + // CheckStyle:VisibilityModifier OFF - bc + protected String taskString = ""; + // CheckStyle:VisibilityModifier ON + + /** + * Execute the subtask. + * @param rexec the client + * @throws BuildException always as it is not allowed to instantiate this object + */ + public void execute(AntRExecClient rexec) + throws BuildException { + throw new BuildException("Shouldn't be able instantiate a SubTask directly"); + } + + /** + * the message as nested text + * @param s the nested text + */ + public void addText(String s) { + setString(getProject().replaceProperties(s)); + } + + /** + * the message as an attribute + * @param s a <code>String</code> value + */ + public void setString(String s) { + taskString += s; + } + } + + /** + * Sends text to the connected server + */ + public class RExecWrite extends RExecSubTask { + private boolean echoString = true; + /** + * Execute the write exec task. + * @param rexec the task to use + * @throws BuildException on error + */ + public void execute(AntRExecClient rexec) + throws BuildException { + rexec.sendString(taskString, echoString); + } + + /** + * Whether or not the message should be echoed to the log. + * Defaults to <code>true</code>. + * @param b a <code>boolean</code> value + */ + public void setEcho(boolean b) { + echoString = b; + } + } + + /** + * Reads the output from the connected server + * until the required string is found or we time out. + */ + public class RExecRead extends RExecSubTask { + private Integer timeout = null; + /** + * Execute the read exec task. + * @param rexec the task to use + * @throws BuildException on error + */ + public void execute(AntRExecClient rexec) + throws BuildException { + rexec.waitForString(taskString, timeout); + } + /** + * a timeout value that overrides any task wide timeout. + * @param i an <code>Integer</code> value + */ + public void setTimeout(Integer i) { + this.timeout = i; + } + + /** + * Sets the default timeout if none has been set already + * @param defaultTimeout an <code>Integer</code> value + * @ant.attribute ignore="true" + */ + public void setDefaultTimeout(Integer defaultTimeout) { + if (timeout == null) { + timeout = defaultTimeout; + } + } + } + + /** + * This class handles the abstraction of the rexec protocol. + * Currently it is a wrapper around <a + * href="http://jakarta.apache.org/commons/net/index.html">Jakarta + * Commons Net</a>. + */ + public class AntRExecClient extends RExecClient { + /** + * Read from the rexec session until the string we are + * waiting for is found + * @param s The string to wait on + */ + public void waitForString(String s) { + waitForString(s, null); + } + + /** + * Read from the rexec session until the string we are + * waiting for is found or the timeout has been reached + * @param s The string to wait on + * @param timeout The maximum number of seconds to wait + */ + public void waitForString(String s, Integer timeout) { + InputStream is = this.getInputStream(); + try { + StringBuffer sb = new StringBuffer(); + int windowStart = -s.length(); + if (timeout == null || timeout.intValue() == 0) { + while (windowStart < 0 + || !sb.substring(windowStart).equals(s)) { + sb.append((char) is.read()); + windowStart++; + } + } else { + Calendar endTime = Calendar.getInstance(); + endTime.add(Calendar.SECOND, timeout.intValue()); + while (windowStart < 0 + || !sb.substring(windowStart).equals(s)) { + while (Calendar.getInstance().before(endTime) + && is.available() == 0) { + Thread.sleep(PAUSE_TIME); + } + if (is.available() == 0) { + throw new BuildException( + "Response timed-out waiting for \"" + s + '\"', + getLocation()); + } + sb.append((char) is.read()); + windowStart++; + } + } + log(sb.toString(), Project.MSG_INFO); + } catch (BuildException be) { + throw be; + } catch (Exception e) { + throw new BuildException(e, getLocation()); + } + } + + /** + * Write this string to the rexec session. + * @param s the string to write + * @param echoString if true log the string sent + */ + public void sendString(String s, boolean echoString) { + OutputStream os = this.getOutputStream(); + try { + os.write((s + "\n").getBytes()); + if (echoString) { + log(s, Project.MSG_INFO); + } + os.flush(); + } catch (Exception e) { + throw new BuildException(e, getLocation()); + } + } + /** + * Read from the rexec session until the EOF is found or + * the timeout has been reached + * @param timeout The maximum number of seconds to wait + */ + public void waitForEOF(Integer timeout) { + InputStream is = this.getInputStream(); + try { + StringBuffer sb = new StringBuffer(); + if (timeout == null || timeout.intValue() == 0) { + int read; + while ((read = is.read()) != -1) { + char c = (char) read; + sb.append(c); + if (c == '\n') { + log(sb.toString(), Project.MSG_INFO); + sb.delete(0, sb.length()); + } + } + } else { + Calendar endTime = Calendar.getInstance(); + endTime.add(Calendar.SECOND, timeout.intValue()); + int read = 0; + while (read != -1) { + while (Calendar.getInstance().before(endTime) && is.available() == 0) { + Thread.sleep(PAUSE_TIME); + } + if (is.available() == 0) { + log(sb.toString(), Project.MSG_INFO); + throw new BuildException( + "Response timed-out waiting for EOF", + getLocation()); + } + read = is.read(); + if (read != -1) { + char c = (char) read; + sb.append(c); + if (c == '\n') { + log(sb.toString(), Project.MSG_INFO); + sb.delete(0, sb.length()); + } + } + } + } + if (sb.length() > 0) { + log(sb.toString(), Project.MSG_INFO); + } + } catch (BuildException be) { + throw be; + } catch (Exception e) { + throw new BuildException(e, getLocation()); + } + } + + } + /** + * A string to wait for from the server. + * A subTask <read> tag was found. Create the object, + * Save it in our list, and return it. + * @return a read sub task + */ + + public RExecSubTask createRead() { + RExecSubTask task = (RExecSubTask) new RExecRead(); + rexecTasks.addElement(task); + return task; + } + /** + * Add text to send to the server + * A subTask <write> tag was found. Create the object, + * Save it in our list, and return it. + * @return a write sub task + */ + public RExecSubTask createWrite() { + RExecSubTask task = (RExecSubTask) new RExecWrite(); + rexecTasks.addElement(task); + return task; + } + /** + * Verify that all parameters are included. + * Connect and possibly login. + * Iterate through the list of Reads and writes. + * @throws BuildException on error + */ + public void execute() throws BuildException { + /** A server name is required to continue */ + if (server == null) { + throw new BuildException("No Server Specified"); + } + /** A userid and password must appear together + * if they appear. They are not required. + */ + if (userid == null && password != null) { + throw new BuildException("No Userid Specified"); + } + if (password == null && userid != null) { + throw new BuildException("No Password Specified"); + } + + /** Create the telnet client object */ + AntRExecClient rexec = null; + try { + rexec = new AntRExecClient(); + try { + rexec.connect(server, port); + } catch (IOException e) { + throw new BuildException("Can't connect to " + server); + } + if (userid != null && password != null && command != null + && rexecTasks.size() == 0) { + // simple one-shot execution + rexec.rexec(userid, password, command); + } else { + // need nested read/write elements + handleMultipleTasks(rexec); + } + + /** Keep reading input stream until end of it or time-out */ + rexec.waitForEOF(defaultTimeout); + } catch (IOException e) { + throw new BuildException("Error r-executing command", e); + } finally { + if (rexec != null && rexec.isConnected()) { + try { + rexec.disconnect(); + } catch (IOException e) { + throw new BuildException("Error disconnecting from " + + server); + } + } + } + } + /** + * Process a 'typical' login. If it differs, use the read + * and write tasks explicitly + */ + private void login(AntRExecClient rexec) { + if (addCarriageReturn) { + rexec.sendString("\n", true); + } + rexec.waitForString("ogin:"); + rexec.sendString(userid, true); + rexec.waitForString("assword:"); + rexec.sendString(password, false); + } + /** + * Set the the command to execute on the server; + * @param c a <code>String</code> value + */ + public void setCommand(String c) { + this.command = c; + } + + /** + * send a carriage return after connecting; optional, defaults to false. + * @param b a <code>boolean</code> value + */ + public void setInitialCR(boolean b) { + this.addCarriageReturn = b; + } + /** + * Set the the login password to use + * required if <tt>userid</tt> is set. + * @param p a <code>String</code> value + */ + public void setPassword(String p) { + this.password = p; + } + + /** + * Set the tcp port to connect to; default is 23. + * @param p an <code>int</code> value + */ + public void setPort(int p) { + this.port = p; + } + + /** + * Set the hostname or address of the remote server. + * @param m a <code>String</code> value + */ + public void setServer(String m) { + this.server = m; + } + + /** + * set a default timeout in seconds to wait for a response, + * zero means forever (the default) + * @param i an <code>Integer</code> value + */ + public void setTimeout(Integer i) { + this.defaultTimeout = i; + } + /** + * Set the the login id to use on the server; + * required if <tt>password</tt> is set. + * @param u a <code>String</code> value + */ + public void setUserid(String u) { + this.userid = u; + } + + /** + * Deals with multiple read/write calls. + * + * @since Ant 1.6.3 + */ + private void handleMultipleTasks(AntRExecClient rexec) { + + /** Login if userid and password were specified */ + if (userid != null && password != null) { + login(rexec); + } + /** Process each sub command */ + Enumeration tasksToRun = rexecTasks.elements(); + while (tasksToRun != null && tasksToRun.hasMoreElements()) { + RExecSubTask task = (RExecSubTask) tasksToRun.nextElement(); + if (task instanceof RExecRead && defaultTimeout != null) { + ((RExecRead) task).setDefaultTimeout(defaultTimeout); + } + task.execute(rexec); + } + } +} |