1 package org
.argeo
.slc
.jsch
;
3 import java
.io
.ByteArrayInputStream
;
4 import java
.io
.ByteArrayOutputStream
;
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
;
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
;
24 import com
.jcraft
.jsch
.Channel
;
25 import com
.jcraft
.jsch
.ChannelExec
;
26 import com
.jcraft
.jsch
.Session
;
28 public class ScpTo
extends AbstractJschTask
{
29 private final static Log log
= LogFactory
.getLog(ScpTo
.class);
31 private Resource localResource
;
32 private String remotePath
;
35 private String remoteDir
;
36 private List
<String
> includes
= new ArrayList
<String
>();
38 private List
<String
> excludes
= new ArrayList
<String
>();
40 private PathMatcher pathMatcher
;
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.");
47 String dirOs
= dir
.replace('/', File
.separatorChar
);
48 if (dirOs
.charAt(dir
.length() - 1) != File
.separatorChar
) {
49 dirOs
= dirOs
+ File
.separator
;
52 if (pathMatcher
== null)
53 pathMatcher
= new AntPathMatcher();
55 log
.info("Start multiple scp based on " + dirOs
);
56 scanDir(session
, dirOs
, "", includes
, excludes
);
59 if (localResource
!= null) {
60 uploadResource(session
, localResource
);
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
);
74 String relPath
= currentRelPath
.concat(file
.getName()).concat(
76 if (match(relPath
, includes
, excludes
, true)) {
77 String nextDir
= dir
.concat(file
.getName()).concat(
79 scanDir(session
, nextDir
, relPath
, includes
, excludes
);
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
);
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
,
110 protected void uploadFile(Session session
, File file
, String remoteFile
) {
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
);
119 protected void uploadResource(Session session
, Resource resource
) {
120 String targetPath
= remotePath
!= null ? remotePath
: remoteDir
+ '/'
121 + resource
.getFilename();
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;
132 if (resource
instanceof ByteArrayResource
) {
133 arr
= ((ByteArrayResource
) resource
).getByteArray();
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);
144 ByteArrayInputStream content
= new ByteArrayInputStream(arr
);
145 upload(session
, content
, arr
.length
, path
, resource
.toString(),
148 } catch (IOException e1
) {
149 throw new SlcException("Can not interpret resource "
150 + localResource
, e1
);
152 IOUtils
.closeQuietly(in
);
153 // no need to close byte arrays streams
158 protected void upload(Session session
, InputStream in
, long size
,
159 String path
, String sourceDesc
, String remoteFile
) {
160 OutputStream channelOut
;
161 InputStream channelIn
;
164 // exec 'scp -t rfile' remotely
165 String command
= "scp -p -t " + remoteFile
;
166 Channel channel
= session
.openChannel("exec");
167 ((ChannelExec
) channel
).setCommand(command
);
169 // get I/O streams for remote scp
170 channelOut
= channel
.getOutputStream();
171 channelIn
= channel
.getInputStream();
176 // send "C0644 filesize filename", where filename should not include
178 long filesize
= size
;
179 command
= "C0644 " + filesize
+ " ";
180 int index
= path
.lastIndexOf('/');
182 command
+= path
.substring(index
+ 1);
188 channelOut
.write(command
.getBytes());
192 if (log
.isTraceEnabled())
193 log
.debug("Start copy of " + sourceDesc
+ " to " + remoteFile
194 + " on " + getSshTarget() + "...");
196 final long oneMB
= 1024l;// in KB
197 final long tenMB
= 10 * oneMB
;// in KB
199 // send a content of lfile
200 byte[] buf
= new byte[1024];
204 int len
= in
.read(buf
, 0, buf
.length
);
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
213 System
.out
.print(" - " + cycleCount
/ tenMB
+ "0 MB\n");
218 channelOut
.write(buf
, 0, 1);
222 if (log
.isDebugEnabled())
223 log
.debug("Transferred to " + remoteFile
+ " ("
224 + sizeDesc(nbrOfBytes
) + ") on " + getSshTarget()
225 + " from " + sourceDesc
);
227 IOUtils
.closeQuietly(channelOut
);
229 channel
.disconnect();
230 } catch (Exception e
) {
231 throw new SlcException("Cannot copy " + path
+ " to " + remoteFile
,
234 IOUtils
.closeQuietly(in
);
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";
244 return nbrOfBytes
/ (1024 * 1024) + " MB";
247 public void setLocalResource(Resource localFile
) {
248 this.localResource
= localFile
;
251 public void setRemotePath(String remoteFile
) {
252 this.remotePath
= remoteFile
;
255 public void setDir(String dir
) {
259 public void setRemoteDir(String remoteDir
) {
260 this.remoteDir
= remoteDir
;
263 public void setIncludes(List
<String
> includes
) {
264 this.includes
= includes
;
267 public void setExcludes(List
<String
> excludes
) {
268 this.excludes
= excludes
;
271 public void setPathMatcher(PathMatcher pathMatcher
) {
272 this.pathMatcher
= pathMatcher
;