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