]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/SshFilesDeployment.java
add some private constructors with no arg, some getters & setters and some ids to...
[gpl/argeo-slc.git] / runtime / org.argeo.slc.support.simple / src / main / java / org / argeo / slc / jsch / SshFilesDeployment.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.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.StringTokenizer;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.argeo.slc.SlcException;
28 import org.argeo.slc.core.deploy.DigestCheck;
29 import org.argeo.slc.core.deploy.ResourceSet;
30 import org.springframework.core.io.Resource;
31
32 import com.jcraft.jsch.Session;
33
34 public class SshFilesDeployment extends AbstractJschTask implements Runnable {
35 private final static Log log = LogFactory.getLog(SshFilesDeployment.class);
36 private String targetBase = "";
37 private ResourceSet resourceSet;
38 /**
39 * Activate with algorithm as per
40 * http://java.sun.com/j2se/1.5.0/docs/guide/security/CryptoSpec.html#AppA
41 */
42 private String checksum = "MD5";
43 private int remoteChecksumsPerCall = 20;
44
45 public SshFilesDeployment() {
46 }
47
48 public SshFilesDeployment(SshTarget sshTarget, ResourceSet resourceSet) {
49 setSshTarget(sshTarget);
50 this.resourceSet = resourceSet;
51 }
52
53 @Override
54 void run(Session session) {
55 JschMultiTasks multiTasks = new JschMultiTasks();
56
57 Map<String, Resource> resources = resourceSet.listResources();
58
59 // Analyze set
60 List<String> subDirs = new ArrayList<String>();
61 Map<String, String> targetPaths = new HashMap<String, String>();
62 for (String relPath : resources.keySet()) {
63 String parentDir;
64 int lastIndexSubDir = relPath.lastIndexOf('/');
65 if (lastIndexSubDir > 0)
66 parentDir = targetBase + '/'
67 + relPath.substring(0, lastIndexSubDir);
68 else
69 parentDir = targetBase;
70
71 boolean skipDir = false;
72 registerDirs: for (String registeredDir : new ArrayList<String>(
73 subDirs)) {
74 if (parentDir.equals(registeredDir)) {
75 if (log.isTraceEnabled())
76 log.trace("Already registered, skip " + parentDir);
77 skipDir = true;
78 break registerDirs;
79 }
80
81 if (parentDir.startsWith(registeredDir))
82 if (subDirs.contains(registeredDir)) {
83 subDirs.remove(registeredDir);
84 if (log.isTraceEnabled())
85 log.trace("Remove parent " + registeredDir + " of "
86 + parentDir);
87 continue registerDirs;
88 }
89
90 if (registeredDir.startsWith(parentDir)) {
91 skipDir = true;
92 if (log.isTraceEnabled())
93 log.trace("Skip " + parentDir
94 + " because child already registered.");
95 break registerDirs;
96 }
97 }
98
99 if (!subDirs.contains(parentDir) && !skipDir) {
100 subDirs.add(parentDir);
101 }
102
103 targetPaths.put(relPath, targetBase + "/" + relPath);
104 }
105
106 // checksum
107 List<String> targetPathsEqualsToLocal = new ArrayList<String>();
108 if (checksum != null) {
109 Map<String, String> remoteChecksums = new HashMap<String, String>();
110 List<String> csLines = new ArrayList<String>();
111 String csExecutable;
112 if ("MD5".equals(checksum))
113 csExecutable = "/usr/bin/md5sum";
114 else if ("SHA".equals(checksum))
115 csExecutable = "/usr/bin/sha1sum";
116 else if ("SHA-256".equals(checksum))
117 csExecutable = "/usr/bin/sha256sum";
118 else if ("SHA-512".equals(checksum))
119 csExecutable = "/usr/bin/sha512sum";
120 else
121 throw new SlcException(
122 "Don't know how to remotely execute checksum "
123 + checksum);
124
125 StringBuffer csCmd = new StringBuffer(csExecutable);
126 int numberOfPaths = targetPaths.size();
127 int count = 0;
128 for (String targetPath : targetPaths.values()) {
129 csCmd.append(" ").append(targetPath);
130 count++;
131
132 if ((count % remoteChecksumsPerCall == 0)
133 || count == numberOfPaths) {
134 RemoteExec remoteCs = new RemoteExec();
135 remoteCs.setSshTarget(getSshTarget());
136 remoteCs.setCommand(csCmd.toString());
137 remoteCs.setStdOutLines(csLines);
138 remoteCs.setFailOnBadExitStatus(false);
139 remoteCs.run(session);
140 csCmd = new StringBuffer(csExecutable);
141 }
142
143 }
144
145 remoteChecksums: for (String csLine : csLines) {
146 StringTokenizer st = new StringTokenizer(csLine, ": ");
147 String cs = st.nextToken();
148 if (cs.equals(csExecutable)) {
149 // remote does not exist
150 continue remoteChecksums;
151 } else {
152 String targetPath = st.nextToken();
153 if (log.isTraceEnabled())
154 log.trace("REMOTE: " + targetPath + "=" + cs);
155 remoteChecksums.put(targetPath, cs);
156 }
157 }
158
159 // Local checksums
160 for (String relPath : resources.keySet()) {
161 Resource resource = resources.get(relPath);
162 String targetPath = targetPaths.get(relPath);
163 if (remoteChecksums.containsKey(targetPath)) {
164 String cs = DigestCheck.digest(checksum, resource);
165 if (log.isTraceEnabled())
166 log.trace("LOCAL : " + targetPath + "=" + cs);
167 if (remoteChecksums.get(targetPath).equals(cs))
168 targetPathsEqualsToLocal.add(targetPath);
169 }
170 }
171 }
172
173 // Prepare multitask
174
175 // Create dirs
176 StringBuffer mkdirCmd = new StringBuffer("mkdir -p");
177 RemoteExec remoteExec = new RemoteExec();
178 for (String dir : subDirs) {
179 // remoteExec.getCommands().add("mkdir -p " + dir);
180 mkdirCmd.append(' ');
181 if (dir.indexOf(' ') >= 0)
182 mkdirCmd.append('\"').append(dir).append('\"');
183 else
184 mkdirCmd.append(dir);
185 }
186 remoteExec.setCommand(mkdirCmd.toString());
187 multiTasks.getTasks().add(remoteExec);
188
189 // Perform copies
190 int copied = 0;
191 int skipped = 0;
192 copy: for (String relPath : resources.keySet()) {
193 String targetPath = targetPaths.get(relPath);
194 if (targetPathsEqualsToLocal.contains(targetPath)) {
195 if (log.isTraceEnabled())
196 log.trace("Skip copy of " + relPath
197 + " since it is equal to remote " + targetPath);
198 skipped++;
199 continue copy;
200 }
201 // Copy resource
202 Resource resource = resources.get(relPath);
203 ScpTo scpTo = new ScpTo();
204 scpTo.setLocalResource(resource);
205 scpTo.setRemotePath(targetPath);
206 multiTasks.getTasks().add(scpTo);
207 copied++;
208 // TODO: set permissions
209 }
210
211 multiTasks.setSshTarget(getSshTarget());
212 multiTasks.run(session);
213
214 if (checksum != null && log.isDebugEnabled())
215 log.debug("Copied " + copied + " files, skipped " + skipped
216 + " with same checksum.");
217 }
218
219 public void setTargetBase(String targetBase) {
220 this.targetBase = targetBase;
221 }
222
223 public void setResourceSet(ResourceSet resourceSet) {
224 this.resourceSet = resourceSet;
225 }
226
227 public void setChecksum(String checksum) {
228 this.checksum = checksum;
229 }
230
231 /** Number of remote checksums per remote call */
232 public void setRemoteChecksumsPerCall(int remoteChecksumsPerCall) {
233 this.remoteChecksumsPerCall = remoteChecksumsPerCall;
234 }
235 }