2 * Copyright (C) 2007-2012 Argeo GmbH
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.slc
.jsch
;
18 import java
.io
.ByteArrayInputStream
;
19 import java
.io
.ByteArrayOutputStream
;
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
;
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
;
39 import com
.jcraft
.jsch
.Channel
;
40 import com
.jcraft
.jsch
.ChannelExec
;
41 import com
.jcraft
.jsch
.Session
;
43 public class ScpTo
extends AbstractJschTask
{
44 private final static Log log
= LogFactory
.getLog(ScpTo
.class);
46 private Resource localResource
;
47 private String remotePath
;
50 private String remoteDir
;
51 private List
<String
> includes
= new ArrayList
<String
>();
53 private List
<String
> excludes
= new ArrayList
<String
>();
55 private PathMatcher pathMatcher
;
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.");
62 String dirOs
= dir
.replace('/', File
.separatorChar
);
63 if (dirOs
.charAt(dir
.length() - 1) != File
.separatorChar
) {
64 dirOs
= dirOs
+ File
.separator
;
67 if (pathMatcher
== null)
68 pathMatcher
= new AntPathMatcher();
70 log
.info("Start multiple scp based on " + dirOs
);
71 scanDir(session
, dirOs
, "", includes
, excludes
);
74 if (localResource
!= null) {
75 uploadResource(session
, localResource
);
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
);
89 String relPath
= currentRelPath
.concat(file
.getName()).concat(
91 if (match(relPath
, includes
, excludes
, true)) {
92 String nextDir
= dir
.concat(file
.getName()).concat(
94 scanDir(session
, nextDir
, relPath
, includes
, excludes
);
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
);
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
,
125 protected void uploadFile(Session session
, File file
, String remoteFile
) {
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
);
134 protected void uploadResource(Session session
, Resource resource
) {
135 String targetPath
= remotePath
!= null ? remotePath
: remoteDir
+ '/'
136 + resource
.getFilename();
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;
147 if (resource
instanceof ByteArrayResource
) {
148 arr
= ((ByteArrayResource
) resource
).getByteArray();
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);
159 ByteArrayInputStream content
= new ByteArrayInputStream(arr
);
160 upload(session
, content
, arr
.length
, path
, resource
.toString(),
163 } catch (IOException e1
) {
164 throw new SlcException("Can not interpret resource "
165 + localResource
, e1
);
167 IOUtils
.closeQuietly(in
);
168 // no need to close byte arrays streams
173 protected void upload(Session session
, InputStream in
, long size
,
174 String path
, String sourceDesc
, String remoteFile
) {
175 OutputStream channelOut
;
176 InputStream channelIn
;
179 // exec 'scp -t rfile' remotely
180 String command
= "scp -p -t " + remoteFile
;
181 Channel channel
= session
.openChannel("exec");
182 ((ChannelExec
) channel
).setCommand(command
);
184 // get I/O streams for remote scp
185 channelOut
= channel
.getOutputStream();
186 channelIn
= channel
.getInputStream();
191 // send "C0644 filesize filename", where filename should not include
193 long filesize
= size
;
194 command
= "C0644 " + filesize
+ " ";
195 int index
= path
.lastIndexOf('/');
197 command
+= path
.substring(index
+ 1);
203 channelOut
.write(command
.getBytes());
207 if (log
.isTraceEnabled())
208 log
.debug("Start copy of " + sourceDesc
+ " to " + remoteFile
209 + " on " + getSshTarget() + "...");
211 final long oneMB
= 1024l;// in KB
212 final long tenMB
= 10 * oneMB
;// in KB
214 // send a content of lfile
215 byte[] buf
= new byte[1024];
219 int len
= in
.read(buf
, 0, buf
.length
);
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
228 System
.out
.print(" - " + cycleCount
/ tenMB
+ "0 MB\n");
233 channelOut
.write(buf
, 0, 1);
237 if (log
.isDebugEnabled())
238 log
.debug("Transferred to " + remoteFile
+ " ("
239 + sizeDesc(nbrOfBytes
) + ") on " + getSshTarget()
240 + " from " + sourceDesc
);
242 IOUtils
.closeQuietly(channelOut
);
244 channel
.disconnect();
245 } catch (Exception e
) {
246 throw new SlcException("Cannot copy " + path
+ " to " + remoteFile
,
249 IOUtils
.closeQuietly(in
);
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";
259 return nbrOfBytes
/ (1024 * 1024) + " MB";
262 public void setLocalResource(Resource localFile
) {
263 this.localResource
= localFile
;
266 public void setRemotePath(String remoteFile
) {
267 this.remotePath
= remoteFile
;
270 public void setDir(String dir
) {
274 public void setRemoteDir(String remoteDir
) {
275 this.remoteDir
= remoteDir
;
278 public void setIncludes(List
<String
> includes
) {
279 this.includes
= includes
;
282 public void setExcludes(List
<String
> excludes
) {
283 this.excludes
= excludes
;
286 public void setPathMatcher(PathMatcher pathMatcher
) {
287 this.pathMatcher
= pathMatcher
;