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