View Javadoc
1   /*
2    * Copyright (C) 2007-2012 Argeo GmbH
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  package org.argeo.slc.jsch;
17  
18  import java.io.File;
19  import java.io.FileOutputStream;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.OutputStream;
23  
24  import org.apache.commons.io.IOUtils;
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.argeo.slc.SlcException;
28  import org.springframework.core.io.Resource;
29  
30  import com.jcraft.jsch.Channel;
31  import com.jcraft.jsch.ChannelExec;
32  import com.jcraft.jsch.Session;
33  
34  public class ScpFrom extends AbstractJschTask {
35  	private final static Log log = LogFactory.getLog(ScpFrom.class);
36  
37  	private Resource localResource;
38  	private String remotePath;
39  	private Boolean mkdir = false;
40  
41  	public void run(Session session) {
42  		if (localResource != null) {
43  			File lFile;
44  			try {
45  				lFile = localResource.getFile();
46  			} catch (IOException e) {
47  				throw new SlcException("Cannot interpret resource "
48  						+ localResource + " as file.", e);
49  			}
50  			downloadFile(session, lFile, remotePath);
51  		}
52  	}
53  
54  	protected void downloadFile(Session session, File localFile,
55  			String remoteFile) {
56  		OutputStream out = null;
57  		OutputStream channelOut;
58  		InputStream channelIn;
59  		try {
60  			// exec 'scp -f rfile' remotely
61  			String command = "scp -f " + remoteFile;
62  			Channel channel = session.openChannel("exec");
63  			((ChannelExec) channel).setCommand(command);
64  
65  			// get I/O streams for remote scp
66  			channelOut = channel.getOutputStream();
67  			channelIn = channel.getInputStream();
68  
69  			channel.connect();
70  
71  			byte[] buf = new byte[1024];
72  
73  			// send '\0'
74  			buf[0] = 0;
75  			channelOut.write(buf, 0, 1);
76  			channelOut.flush();
77  
78  			while (true) {
79  				int c = checkAck(channelIn);
80  				if (c != 'C') {
81  					break;
82  				}
83  
84  				// read '0644 '
85  				channelIn.read(buf, 0, 5);
86  
87  				long filesize = 0L;
88  				while (true) {
89  					if (channelIn.read(buf, 0, 1) < 0) {
90  						// error
91  						break;
92  					}
93  					if (buf[0] == ' ')
94  						break;
95  					filesize = filesize * 10L + (long) (buf[0] - '0');
96  				}
97  
98  				String remoteFileName = null;
99  				for (int i = 0;; i++) {
100 					channelIn.read(buf, i, 1);
101 					if (buf[i] == (byte) 0x0a) {
102 						remoteFileName = new String(buf, 0, i);
103 						break;
104 					}
105 				}
106 
107 				// System.out.println("filesize="+filesize+", file="+file);
108 
109 				// send '\0'
110 				buf[0] = 0;
111 				channelOut.write(buf, 0, 1);
112 				channelOut.flush();
113 
114 				// Create a s adirectory if it doesn't exists
115 				if (!localFile.exists() && mkdir)
116 					localFile.mkdirs();
117 
118 				// read a content of lfile
119 				String localPath = localFile.isDirectory() ? localFile
120 						.getPath()
121 						+ File.separator + remoteFileName : localFile.getPath();
122 
123 				out = new FileOutputStream(localPath);
124 				int foo;
125 				while (true) {
126 					if (buf.length < filesize)
127 						foo = buf.length;
128 					else
129 						foo = (int) filesize;
130 					foo = channelIn.read(buf, 0, foo);
131 					if (foo < 0) {
132 						// error
133 						break;
134 					}
135 					out.write(buf, 0, foo);
136 					filesize -= foo;
137 					if (filesize == 0L)
138 						break;
139 				}
140 
141 				checkAck(channelIn);
142 
143 				// send '\0'
144 				buf[0] = 0;
145 				channelOut.write(buf, 0, 1);
146 				channelOut.flush();
147 
148 				if (log.isDebugEnabled())
149 					log.debug("Finished downloading " + remoteFile + " on "
150 							+ getSshTarget() + " to " + localPath);
151 			}
152 
153 			channel.disconnect();
154 			// session.disconnect();
155 		} catch (Exception e) {
156 			throw new SlcException("Cannot download " + remoteFile + " to "
157 					+ localFile, e);
158 		} finally {
159 			IOUtils.closeQuietly(out);
160 		}
161 	}
162 
163 	public void setLocalResource(Resource localFile) {
164 		this.localResource = localFile;
165 	}
166 
167 	public void setRemotePath(String remoteFile) {
168 		this.remotePath = remoteFile;
169 	}
170 
171 	public void setMkdir(Boolean mkdir) {
172 		this.mkdir = mkdir;
173 	}
174 }