KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > fr > jayasoft > ivy > repository > ssh > SshRepository


1 package fr.jayasoft.ivy.repository.ssh;
2
3
4 import java.io.BufferedReader JavaDoc;
5 import java.io.ByteArrayInputStream JavaDoc;
6 import java.io.ByteArrayOutputStream JavaDoc;
7 import java.io.File JavaDoc;
8 import java.io.IOException JavaDoc;
9 import java.io.InputStream JavaDoc;
10 import java.io.StringReader JavaDoc;
11 import java.net.URI JavaDoc;
12 import java.net.URISyntaxException JavaDoc;
13 import java.util.ArrayList JavaDoc;
14 import java.util.List JavaDoc;
15
16 import com.jcraft.jsch.ChannelExec;
17 import com.jcraft.jsch.JSchException;
18 import com.jcraft.jsch.Session;
19
20 import fr.jayasoft.ivy.repository.Resource;
21 import fr.jayasoft.ivy.util.Message;
22
23 /**
24  * Ivy Repository based on SSH
25  */

26 public class SshRepository extends AbstractSshBasedRepository {
27
28     private char fileSeparator = '/';
29     private String JavaDoc listCommand = "ls -1";
30     private String JavaDoc existCommand = "ls";
31     private String JavaDoc createDirCommand = "mkdir";
32     private final static String JavaDoc ARGUMENT_PLACEHOLDER = "%arg";
33     private final static int POLL_SLEEP_TIME = 500;
34     /**
35      * create a new resource with lazy initializing
36      */

37     public Resource getResource(String JavaDoc source) {
38         Message.debug("SShRepository:getResource called: "+source);
39         return new SshResource(this,source);
40     }
41     
42     /**
43      * fetch the needed file information for a given file (size, last modification time)
44      * and report it back in a SshResource
45      * @param uri ssh uri for the file to get info for
46      * @return SshResource filled with the needed informations
47      * @see fr.jayasoft.ivy.repository.Repository#getResource(java.lang.String)
48      */

49     public SshResource resolveResource(String JavaDoc source) {
50         Message.debug("SShRepository:resolveResource called: "+source);
51         SshResource result = null;
52         Session session = null;
53         try {
54             session = getSession(source);
55             Scp myCopy = new Scp(session);
56             Scp.FileInfo fileInfo = myCopy.getFileinfo(new URI JavaDoc(source).getPath());
57             result = new SshResource(this,
58                                      source,
59                                      true,
60                                      fileInfo.getLength(),
61                                      fileInfo.getLastModified());
62         } catch (IOException JavaDoc e) {
63             if(session != null)
64                 releaseSession(session,source);
65             result = new SshResource();
66         } catch (URISyntaxException JavaDoc e) {
67              if(session != null)
68                  releaseSession(session,source);
69              result = new SshResource();
70         } catch (RemoteScpException e) {
71             result = new SshResource();
72         }
73         Message.debug("SShRepository:resolveResource end.");
74         return result;
75     }
76
77     /**
78      * Reads out the output of a ssh session exec
79      * @param channel Channel to read from
80      * @param strStdout StringBuffer that receives Session Stdout output
81      * @param strStderr StringBuffer that receives Session Stderr output
82      * @throws IOException in case of trouble with the network
83      */

84     private void readSessionOutput(ChannelExec channel, StringBuffer JavaDoc strStdout, StringBuffer JavaDoc strStderr) throws IOException JavaDoc {
85         InputStream JavaDoc stdout = channel.getInputStream();
86         InputStream JavaDoc stderr = channel.getErrStream();
87         
88         try {
89             channel.connect();
90         } catch (JSchException e1) {
91             throw (IOException JavaDoc) new IOException JavaDoc("Channel connection problems").initCause(e1);
92         }
93         
94         byte[] buffer = new byte[8192];
95         while(true){
96             int avail = 0;
97             while ((avail = stdout.available()) > 0) {
98                 int len = stdout.read(buffer,0,(avail > 8191 ? 8192 : avail));
99                 strStdout.append(new String JavaDoc(buffer,0,len));
100             }
101             while ((avail = stderr.available()) > 0) {
102                 int len = stderr.read(buffer,0,(avail > 8191 ? 8192 : avail));
103                 strStderr.append(new String JavaDoc(buffer, 0, len));
104             }
105             if(channel.isClosed()){
106                 break;
107             }
108             try{Thread.sleep(POLL_SLEEP_TIME);}catch(Exception JavaDoc ee){}
109         }
110         int avail = 0;
111         while ((avail = stdout.available()) > 0) {
112             int len = stdout.read(buffer,0,(avail > 8191 ? 8192 : avail));
113             strStdout.append(new String JavaDoc(buffer,0,len));
114         }
115         while ((avail = stderr.available()) > 0) {
116             int len = stderr.read(buffer,0,(avail > 8191 ? 8192 : avail));
117             strStderr.append(new String JavaDoc(buffer, 0, len));
118         }
119     }
120
121     /* (non-Javadoc)
122      * @see fr.jayasoft.ivy.repository.Repository#list(java.lang.String)
123      */

124     public List JavaDoc list(String JavaDoc parent) throws IOException JavaDoc {
125         Message.debug("SShRepository:list called: "+parent);
126         ArrayList JavaDoc result = new ArrayList JavaDoc();
127         Session session = null;
128         ChannelExec channel = null;
129         session = getSession(parent);
130         channel = getExecChannel(session);
131         URI JavaDoc parentUri = null;
132         try {
133             parentUri = new URI JavaDoc(parent);
134         } catch (URISyntaxException JavaDoc e1) {
135             // failed earlier
136
}
137         String JavaDoc fullCmd = replaceArgument(listCommand,parentUri.getPath());
138         channel.setCommand(fullCmd);
139         StringBuffer JavaDoc stdOut = new StringBuffer JavaDoc();
140         StringBuffer JavaDoc stdErr = new StringBuffer JavaDoc();
141         readSessionOutput(channel,stdOut,stdErr);
142         if(channel.getExitStatus() != 0) {
143             Message.error("Ssh ListCommand exited with status != 0");
144             Message.error(stdErr.toString());
145             return null;
146         } else {
147             BufferedReader JavaDoc br = new BufferedReader JavaDoc(new StringReader JavaDoc(stdOut.toString()));
148             String JavaDoc line = null;
149             while((line = br.readLine()) != null) {
150                 result.add(line);
151             }
152         }
153         return result;
154     }
155
156     /**
157      * @param session
158      * @return
159      * @throws JSchException
160      */

161     private ChannelExec getExecChannel(Session session) throws IOException JavaDoc {
162         ChannelExec channel;
163         try {
164             channel = (ChannelExec)session.openChannel("exec");
165         } catch (JSchException e) {
166             throw new IOException JavaDoc();
167         }
168         return channel;
169     }
170
171     /**
172      * Replace the argument placeholder with argument or append the argument if no
173      * placeholder is present
174      * @param command with argument placeholder or not
175      * @param argument
176      * @return replaced full command
177      */

178     private String JavaDoc replaceArgument(String JavaDoc command, String JavaDoc argument) {
179         String JavaDoc fullCmd;
180         if(command.indexOf(ARGUMENT_PLACEHOLDER) == -1) {
181             fullCmd = command + " " + argument;
182         } else {
183             fullCmd = command.replaceAll(ARGUMENT_PLACEHOLDER,argument);
184         }
185         return fullCmd;
186     }
187
188     /* (non-Javadoc)
189      * @see fr.jayasoft.ivy.repository.Repository#put(java.io.File, java.lang.String, boolean)
190      */

191     public void put(File JavaDoc source, String JavaDoc destination, boolean overwrite) throws IOException JavaDoc {
192         Message.debug("SShRepository:put called: "+destination);
193         Session session = getSession(destination);
194         try {
195             URI JavaDoc destinationUri = null;
196             try {
197                 destinationUri = new URI JavaDoc(destination);
198             } catch (URISyntaxException JavaDoc e) {
199                 // failed earlier in getSession()
200
}
201             String JavaDoc filePath = destinationUri.getPath();
202             int lastSep = filePath.lastIndexOf(fileSeparator);
203             String JavaDoc path;
204             String JavaDoc name;
205             if(lastSep == -1) {
206                 name = filePath;
207                 path = null;
208             } else {
209                 name = filePath.substring(lastSep+1);
210                 path = filePath.substring(0,lastSep);
211             }
212             if (!overwrite) {
213                 if(checkExistence(filePath,session)) {
214                     throw new IOException JavaDoc("destination file exists and overwrite == true");
215                 }
216             }
217             if(path != null) {
218                 makePath(path,session);
219             }
220             Scp myCopy = new Scp(session);
221             myCopy.put(source.getCanonicalPath(),path,name);
222         } catch (IOException JavaDoc e) {
223             if(session != null)
224                 releaseSession(session,destination);
225             throw e;
226         } catch (RemoteScpException e) {
227             throw new IOException JavaDoc(e.getMessage());
228         }
229     }
230     
231     /**
232      * Tries to create a directory path on the target system
233      * @param path to create
234      * @param connnection to use
235      */

236     private void makePath(String JavaDoc path, Session session) throws IOException JavaDoc {
237         ChannelExec channel = null;
238         String JavaDoc trimmed = path;
239         try {
240             while(trimmed.length() > 0 && trimmed.charAt(trimmed.length()-1) == fileSeparator)
241                 trimmed = trimmed.substring(0,trimmed.length()-1);
242             if(trimmed.length() == 0 || checkExistence(trimmed,session)) {
243                 return;
244             }
245             int nextSlash = trimmed.lastIndexOf(fileSeparator);
246             if(nextSlash > 0) {
247                 String JavaDoc parent = trimmed.substring(0,nextSlash);
248                 makePath(parent,session);
249             }
250             channel = getExecChannel(session);
251             String JavaDoc mkdir = replaceArgument( createDirCommand, trimmed);
252             Message.debug("SShRepository: trying to create path: " + mkdir);
253             channel.setCommand(mkdir);
254             StringBuffer JavaDoc stdOut = new StringBuffer JavaDoc();
255             StringBuffer JavaDoc stdErr = new StringBuffer JavaDoc();
256             readSessionOutput(channel,stdOut,stdErr);
257         } finally {
258             if(channel != null)
259                 channel.disconnect();
260         }
261     }
262
263     /**
264      * check for existence of file or dir on target system
265      * @param filePath to the object to check
266      * @param session to use
267      * @return true: object exists, false otherwise
268      */

269     private boolean checkExistence(String JavaDoc filePath, Session session) throws IOException JavaDoc {
270         Message.debug("SShRepository: checkExistence called: " + filePath);
271         ChannelExec channel = null;
272         channel = getExecChannel(session);
273         String JavaDoc fullCmd = replaceArgument( existCommand, filePath);
274         channel.setCommand(fullCmd);
275         StringBuffer JavaDoc stdOut = new StringBuffer JavaDoc();
276         StringBuffer JavaDoc stdErr = new StringBuffer JavaDoc();
277         readSessionOutput(channel,stdOut,stdErr);
278         return channel.getExitStatus() == 0;
279     }
280
281     /* (non-Javadoc)
282      * @see fr.jayasoft.ivy.repository.Repository#get(java.lang.String, java.io.File)
283      */

284     public void get(String JavaDoc source, File JavaDoc destination) throws IOException JavaDoc {
285         Message.debug("SShRepository:get called: "+source+" to "+destination.getCanonicalPath());
286         if (destination.getParentFile() != null) {
287             destination.getParentFile().mkdirs();
288         }
289         Session session = getSession(source);
290         try {
291             URI JavaDoc sourceUri = null;
292             try {
293                 sourceUri = new URI JavaDoc(source);
294             } catch (URISyntaxException JavaDoc e) {
295                 // fails earlier
296
}
297             if(sourceUri == null) {
298                 Message.error("could not parse URI "+source);
299                 return;
300             }
301             Scp myCopy = new Scp(session);
302             myCopy.get(sourceUri.getPath(),destination.getCanonicalPath());
303         } catch (IOException JavaDoc e) {
304             if(session != null)
305                 releaseSession(session,source);
306             throw e;
307         } catch (RemoteScpException e) {
308             throw new IOException JavaDoc(e.getMessage());
309         }
310     }
311
312     /**
313      * sets the list command to use for a directory listing
314      * listing must be only the filename and each filename on a separate line
315      * @param cmd to use. default is "ls -1"
316      */

317     public void setListCommand(String JavaDoc cmd) {
318         this.listCommand = cmd.trim();
319     }
320     
321     /**
322      * @return the list command to use
323      */

324     public String JavaDoc getListCommand() {
325         return listCommand;
326     }
327     
328     /**
329      * @return the createDirCommand
330      */

331     public String JavaDoc getCreateDirCommand() {
332         return createDirCommand;
333     }
334
335     /**
336      * @param createDirCommand the createDirCommand to set
337      */

338     public void setCreateDirCommand(String JavaDoc createDirCommand) {
339         this.createDirCommand = createDirCommand;
340     }
341
342     /**
343      * @return the existCommand
344      */

345     public String JavaDoc getExistCommand() {
346         return existCommand;
347     }
348
349     /**
350      * @param existCommand the existCommand to set
351      */

352     public void setExistCommand(String JavaDoc existCommand) {
353         this.existCommand = existCommand;
354     }
355
356     /**
357      * The file separator is the separator to use on the target system
358      * On a unix system it is '/', but I don't know, how this is solved
359      * on different ssh implementations. Using the default might be fine
360      * @param fileSeparator The fileSeparator to use. default '/'
361      */

362     public void setFileSeparator(char fileSeparator) {
363         this.fileSeparator = fileSeparator;
364     }
365
366     /**
367      * return ssh as scheme
368      * use the Resolver type name here?
369      * would be nice if it would be static, so we could use SshResolver.getTypeName()
370      */

371     protected String JavaDoc getRepositoryScheme() {
372         return "ssh";
373     }
374     
375     /**
376      * Not really streaming...need to implement a proper streaming approach?
377      * @param resource to stream
378      * @return InputStream of the resource data
379      */

380     public InputStream JavaDoc openStream(SshResource resource) throws IOException JavaDoc {
381         Session session = getSession(resource.getName());
382         Scp scp = new Scp(session);
383         ByteArrayOutputStream JavaDoc os = new ByteArrayOutputStream JavaDoc();
384         try {
385             scp.get(resource.getName(),os);
386         } catch (IOException JavaDoc e) {
387             if(session != null)
388                 releaseSession(session,resource.getName());
389             throw e;
390         } catch (RemoteScpException e) {
391             throw new IOException JavaDoc(e.getMessage());
392         }
393         return new ByteArrayInputStream JavaDoc(os.toByteArray());
394     }
395 }
396
Popular Tags