001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.tools.ant.taskdefs.optional.ssh;
020:
021: import com.jcraft.jsch.Channel;
022: import com.jcraft.jsch.ChannelExec;
023: import com.jcraft.jsch.JSchException;
024: import com.jcraft.jsch.Session;
025: import com.jcraft.jsch.ChannelSftp;
026: import com.jcraft.jsch.SftpProgressMonitor;
027:
028: import java.io.IOException;
029: import java.io.OutputStream;
030: import java.io.InputStream;
031: import java.text.NumberFormat;
032:
033: import org.apache.tools.ant.BuildException;
034:
035: /**
036: * Abstract class for ssh upload and download
037: */
038: public abstract class AbstractSshMessage {
039:
040: private Session session;
041: private boolean verbose;
042: private LogListener listener = new LogListener() {
043: public void log(String message) {
044: // do nothing;
045: }
046: };
047:
048: /**
049: * Constructor for AbstractSshMessage
050: * @param session the ssh session to use
051: */
052: public AbstractSshMessage(Session session) {
053: this (false, session);
054: }
055:
056: /**
057: * Constructor for AbstractSshMessage
058: * @param verbose if true do verbose logging
059: * @param session the ssh session to use
060: * @since Ant 1.6.2
061: */
062: public AbstractSshMessage(boolean verbose, Session session) {
063: this .verbose = verbose;
064: this .session = session;
065: }
066:
067: /**
068: * Open an ssh channel.
069: * @param command the command to use
070: * @return the channel
071: * @throws JSchException on error
072: */
073: protected Channel openExecChannel(String command)
074: throws JSchException {
075: ChannelExec channel = (ChannelExec) session.openChannel("exec");
076: channel.setCommand(command);
077:
078: return channel;
079: }
080:
081: /**
082: * Open an ssh sftp channel.
083: * @return the channel
084: * @throws JSchException on error
085: */
086: protected ChannelSftp openSftpChannel() throws JSchException {
087: ChannelSftp channel = (ChannelSftp) session.openChannel("sftp");
088:
089: return channel;
090: }
091:
092: /**
093: * Send an ack.
094: * @param out the output stream to use
095: * @throws IOException on error
096: */
097: protected void sendAck(OutputStream out) throws IOException {
098: byte[] buf = new byte[1];
099: buf[0] = 0;
100: out.write(buf);
101: out.flush();
102: }
103:
104: /**
105: * Reads the response, throws a BuildException if the response
106: * indicates an error.
107: * @param in the input stream to use
108: * @throws IOException on I/O error
109: * @throws BuildException on other errors
110: */
111: protected void waitForAck(InputStream in) throws IOException,
112: BuildException {
113: int b = in.read();
114:
115: // b may be 0 for success,
116: // 1 for error,
117: // 2 for fatal error,
118:
119: if (b == -1) {
120: // didn't receive any response
121: throw new BuildException("No response from server");
122: } else if (b != 0) {
123: StringBuffer sb = new StringBuffer();
124:
125: int c = in.read();
126: while (c > 0 && c != '\n') {
127: sb.append((char) c);
128: c = in.read();
129: }
130:
131: if (b == 1) {
132: throw new BuildException("server indicated an error: "
133: + sb.toString());
134: } else if (b == 2) {
135: throw new BuildException(
136: "server indicated a fatal error: "
137: + sb.toString());
138: } else {
139: throw new BuildException("unknown response, code " + b
140: + " message: " + sb.toString());
141: }
142: }
143: }
144:
145: /**
146: * Carry out the transfer.
147: * @throws IOException on I/O errors
148: * @throws JSchException on ssh errors
149: */
150: public abstract void execute() throws IOException, JSchException;
151:
152: /**
153: * Set a log listener.
154: * @param aListener the log listener
155: */
156: public void setLogListener(LogListener aListener) {
157: listener = aListener;
158: }
159:
160: /**
161: * Log a message to the log listener.
162: * @param message the message to log
163: */
164: protected void log(String message) {
165: listener.log(message);
166: }
167:
168: /**
169: * Log transfer stats to the log listener.
170: * @param timeStarted the time started
171: * @param timeEnded the finishing time
172: * @param totalLength the total length
173: */
174: protected void logStats(long timeStarted, long timeEnded,
175: long totalLength) {
176: double duration = (timeEnded - timeStarted) / 1000.0;
177: NumberFormat format = NumberFormat.getNumberInstance();
178: format.setMaximumFractionDigits(2);
179: format.setMinimumFractionDigits(1);
180: listener.log("File transfer time: " + format.format(duration)
181: + " Average Rate: "
182: + format.format(totalLength / duration) + " B/s");
183: }
184:
185: /**
186: * Is the verbose attribute set.
187: * @return true if the verbose attribute is set
188: * @since Ant 1.6.2
189: */
190: protected final boolean getVerbose() {
191: return verbose;
192: }
193:
194: /**
195: * Track progress every 10% if 100kb < filesize < 1mb. For larger
196: * files track progress for every percent transmitted.
197: * @param filesize the size of the file been transmitted
198: * @param totalLength the total transmission size
199: * @param percentTransmitted the current percent transmitted
200: * @return the percent that the file is of the total
201: */
202: protected final int trackProgress(long filesize, long totalLength,
203: int percentTransmitted) {
204:
205: int percent = (int) Math.round(Math
206: .floor((totalLength / (double) filesize) * 100));
207:
208: if (percent > percentTransmitted) {
209: if (filesize < 1048576) {
210: if (percent % 10 == 0) {
211: if (percent == 100) {
212: System.out.println(" 100%");
213: } else {
214: System.out.print("*");
215: }
216: }
217: } else {
218: if (percent == 50) {
219: System.out.println(" 50%");
220: } else if (percent == 100) {
221: System.out.println(" 100%");
222: } else {
223: System.out.print(".");
224: }
225: }
226: }
227:
228: return percent;
229: }
230:
231: private ProgressMonitor monitor = null;
232:
233: /**
234: * Get the progress monitor.
235: * @return the progress monitor.
236: */
237: protected SftpProgressMonitor getProgressMonitor() {
238: if (monitor == null) {
239: monitor = new ProgressMonitor();
240: }
241: return monitor;
242: }
243:
244: private class ProgressMonitor implements SftpProgressMonitor {
245: private long initFileSize = 0;
246: private long totalLength = 0;
247: private int percentTransmitted = 0;
248:
249: public void init(int op, String src, String dest, long max) {
250: initFileSize = max;
251: totalLength = 0;
252: percentTransmitted = 0;
253: }
254:
255: public boolean count(long len) {
256: totalLength += len;
257: percentTransmitted = trackProgress(initFileSize,
258: totalLength, percentTransmitted);
259: return true;
260: }
261:
262: public void end() {
263: }
264:
265: public long getTotalLength() {
266: return totalLength;
267: }
268: }
269: }
|