]> git.argeo.org Git - gpl/argeo-slc.git/blob - org.argeo.slc.support/src/org/argeo/slc/jsch/ScpTo.java
Merge branch 'master' of https://github.com/argeo/argeo-slc.git
[gpl/argeo-slc.git] / org.argeo.slc.support / src / org / argeo / slc / jsch / ScpTo.java
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.ByteArrayInputStream;
19 import java.io.ByteArrayOutputStream;
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.FileNotFoundException;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.OutputStream;
26 import java.util.ArrayList;
27 import java.util.List;
28
29 import org.apache.commons.io.IOUtils;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.argeo.slc.SlcException;
33 import org.springframework.core.io.ByteArrayResource;
34 import org.springframework.core.io.Resource;
35 import org.springframework.util.AntPathMatcher;
36 import org.springframework.util.PathMatcher;
37 import org.springframework.util.StringUtils;
38
39 import com.jcraft.jsch.Channel;
40 import com.jcraft.jsch.ChannelExec;
41 import com.jcraft.jsch.Session;
42
43 public class ScpTo extends AbstractJschTask {
44 private final static Log log = LogFactory.getLog(ScpTo.class);
45
46 private Resource localResource;
47 private String remotePath;
48
49 private String dir;
50 private String remoteDir;
51 private List<String> includes = new ArrayList<String>();
52
53 private List<String> excludes = new ArrayList<String>();
54
55 private PathMatcher pathMatcher;
56
57 public void run(Session session) {
58 if (StringUtils.hasText(dir)) {
59 if (!StringUtils.hasText(remoteDir))
60 throw new SlcException("Remote dir has to be specified.");
61
62 String dirOs = dir.replace('/', File.separatorChar);
63 if (dirOs.charAt(dir.length() - 1) != File.separatorChar) {
64 dirOs = dirOs + File.separator;
65 }
66
67 if (pathMatcher == null)
68 pathMatcher = new AntPathMatcher();
69
70 log.info("Start multiple scp based on " + dirOs);
71 scanDir(session, dirOs, "", includes, excludes);
72 }
73
74 if (localResource != null) {
75 uploadResource(session, localResource);
76 }
77 }
78
79 protected void scanDir(Session session, String dir, String currentRelPath,
80 List<String> includes, List<String> excludes) {
81 File[] files = new File(dir).listFiles();
82 for (File file : files) {
83 if (!file.isDirectory()) {
84 String relPath = currentRelPath.concat(file.getName());
85 if (match(relPath, includes, excludes, false)) {
86 uploadFile(session, file, remoteDir + '/' + relPath);
87 }
88 } else {
89 String relPath = currentRelPath.concat(file.getName()).concat(
90 "/");
91 if (match(relPath, includes, excludes, true)) {
92 String nextDir = dir.concat(file.getName()).concat(
93 File.separator);
94 scanDir(session, nextDir, relPath, includes, excludes);
95 }
96 }
97 }
98 }
99
100 protected Boolean match(String path, List<String> includes,
101 List<String> excludes, boolean matchStart) {
102 for (String patternIn : includes) {
103 boolean matchIn = matchStart ? pathMatcher.matchStart(patternIn,
104 path) : pathMatcher.match(patternIn, path);
105 if (matchIn) {
106 // Could be included, check excludes
107 boolean excluded = false;
108 ex: for (String patternEx : excludes) {
109 boolean matchEx = matchStart ? pathMatcher.matchStart(
110 patternEx, path) : pathMatcher.match(patternEx,
111 path);
112
113 if (matchEx) {
114 excluded = true;
115 break ex;
116 }
117 }
118 if (!excluded)
119 return true;
120 }
121 }
122 return false;
123 }
124
125 protected void uploadFile(Session session, File file, String remoteFile) {
126 try {
127 upload(session, new FileInputStream(file), file.length(), file
128 .getPath(), file.toString(), remoteFile);
129 } catch (FileNotFoundException e) {
130 throw new SlcException("Cannot upload " + file, e);
131 }
132 }
133
134 protected void uploadResource(Session session, Resource resource) {
135 String targetPath = remotePath != null ? remotePath : remoteDir + '/'
136 + resource.getFilename();
137 try {
138 File lFile = resource.getFile();
139 uploadFile(session, lFile, targetPath);
140 } catch (IOException e) {
141 // no underlying file found
142 // load the resource in memory before transferring it
143 InputStream in = null;
144 try {
145 byte[] arr;
146 String path;
147 if (resource instanceof ByteArrayResource) {
148 arr = ((ByteArrayResource) resource).getByteArray();
149 path = "bytearray";
150 } else {
151 in = resource.getInputStream();
152 ByteArrayOutputStream out = new ByteArrayOutputStream();
153 IOUtils.copy(in, out);
154 arr = out.toByteArray();
155 path = resource.getURL().getPath();
156 if (path.startsWith("/"))
157 path = path.substring(1);
158 }
159 ByteArrayInputStream content = new ByteArrayInputStream(arr);
160 upload(session, content, arr.length, path, resource.toString(),
161 targetPath);
162 arr = null;
163 } catch (IOException e1) {
164 throw new SlcException("Can not interpret resource "
165 + localResource, e1);
166 } finally {
167 IOUtils.closeQuietly(in);
168 // no need to close byte arrays streams
169 }
170 }
171 }
172
173 protected void upload(Session session, InputStream in, long size,
174 String path, String sourceDesc, String remoteFile) {
175 OutputStream channelOut;
176 InputStream channelIn;
177 try {
178
179 // exec 'scp -t rfile' remotely
180 String command = "scp -p -t " + remoteFile;
181 Channel channel = session.openChannel("exec");
182 ((ChannelExec) channel).setCommand(command);
183
184 // get I/O streams for remote scp
185 channelOut = channel.getOutputStream();
186 channelIn = channel.getInputStream();
187
188 channel.connect();
189 checkAck(channelIn);
190
191 // send "C0644 filesize filename", where filename should not include
192 // '/'
193 long filesize = size;
194 command = "C0644 " + filesize + " ";
195 int index = path.lastIndexOf('/');
196 if (index > 0) {
197 command += path.substring(index + 1);
198 } else {
199 command += path;
200 }
201 command += "\n";
202
203 channelOut.write(command.getBytes());
204 channelOut.flush();
205 checkAck(channelIn);
206
207 if (log.isTraceEnabled())
208 log.debug("Start copy of " + sourceDesc + " to " + remoteFile
209 + " on " + getSshTarget() + "...");
210
211 final long oneMB = 1024l;// in KB
212 final long tenMB = 10 * oneMB;// in KB
213
214 // send a content of lfile
215 byte[] buf = new byte[1024];
216 long cycleCount = 0;
217 long nbrOfBytes = 0;
218 while (true) {
219 int len = in.read(buf, 0, buf.length);
220 if (len <= 0)
221 break;
222 channelOut.write(buf, 0, len); // out.flush();
223 nbrOfBytes = nbrOfBytes + len;
224 if (((cycleCount % oneMB) == 0) && cycleCount != 0)// each 1 MB
225 System.out.print('#');
226 if (((cycleCount % (tenMB)) == 0) && cycleCount != 0)// each 10
227 // MB
228 System.out.print(" - " + cycleCount / tenMB + "0 MB\n");
229 cycleCount++;
230 }
231 // send '\0'
232 buf[0] = 0;
233 channelOut.write(buf, 0, 1);
234 channelOut.flush();
235 checkAck(channelIn);
236
237 if (log.isDebugEnabled())
238 log.debug("Transferred to " + remoteFile + " ("
239 + sizeDesc(nbrOfBytes) + ") on " + getSshTarget()
240 + " from " + sourceDesc);
241
242 IOUtils.closeQuietly(channelOut);
243
244 channel.disconnect();
245 } catch (Exception e) {
246 throw new SlcException("Cannot copy " + path + " to " + remoteFile,
247 e);
248 } finally {
249 IOUtils.closeQuietly(in);
250 }
251 }
252
253 protected String sizeDesc(Long nbrOfBytes) {
254 if (nbrOfBytes < 1024)
255 return nbrOfBytes + " B";
256 else if (nbrOfBytes < 1024 * 1024)
257 return (nbrOfBytes / 1024) + " KB";
258 else
259 return nbrOfBytes / (1024 * 1024) + " MB";
260 }
261
262 public void setLocalResource(Resource localFile) {
263 this.localResource = localFile;
264 }
265
266 public void setRemotePath(String remoteFile) {
267 this.remotePath = remoteFile;
268 }
269
270 public void setDir(String dir) {
271 this.dir = dir;
272 }
273
274 public void setRemoteDir(String remoteDir) {
275 this.remoteDir = remoteDir;
276 }
277
278 public void setIncludes(List<String> includes) {
279 this.includes = includes;
280 }
281
282 public void setExcludes(List<String> excludes) {
283 this.excludes = excludes;
284 }
285
286 public void setPathMatcher(PathMatcher pathMatcher) {
287 this.pathMatcher = pathMatcher;
288 }
289
290 }