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