View Javadoc

1   /*
2    $Id: FtpStore.java,v 1.2 2004/06/14 23:08:51 jdt Exp $
3   
4    (c) Copyright...
5    */
6   
7   package org.astrogrid.store.delegate.ftp;
8   import org.astrogrid.store.delegate.*;
9   
10  import java.io.*;
11  
12  import java.net.MalformedURLException;
13  import java.net.URL;
14  import java.util.Enumeration;
15  import org.astrogrid.community.User;
16  import org.astrogrid.io.Piper;
17  import org.astrogrid.store.Agsl;
18  import sun.net.ftp.FtpClient;
19  import sun.net.ftp.FtpProtocolException;
20  
21  /***
22   * An implenentation of myspace using an ordinary FTP server.
23   * <P>
24   * Developed using the built-in ftp clients supplied with java - but note
25   * that these are NOT supported directly.
26   * <P>
27   * Adapted from the ACE project
28   * <p>
29   * @deprecated - THIS HAS NOT BEEN PROPERLY MAINTAINED SINCE It04.1
30   */
31  
32  public class FtpStore extends StoreDelegate {
33     
34     private String server = null;
35     private int port = DEFAULT_PORT;
36     private String rootDir = ""; //root directory for this user
37     private URL endpoint = null;
38     
39     private FullFtpClient ftpConnection = null;
40  
41     private final static int DEFAULT_PORT = 21;
42  
43     /***
44      * A more complete FTP client based on sun's
45      *
46      * @version 1.0, 01/19/97, 1.1 6/11/02
47      * @author  Elliotte Rusty Harold, extended further by M C Hill
48      */
49     public class FullFtpClient extends FtpClient {
50  
51        /*** New FullFtpClient connected to host <i>host</i>. */
52        public FullFtpClient(String host) throws IOException {
53           super(host);
54        }
55  
56        /*** New FullFtpClient connected to host <i>host</i>, port <i>port</i>. */
57        public FullFtpClient(String host, int port) throws IOException {
58           super(host, port);
59        }
60  
61        /*** Move up one directory in the ftp file system *
62        public void cdup() throws IOException {
63           issueCommandCheck("CDUP");
64        }
65  
66        /** Create a new directory named s in the ftp file system */
67        public void mkdir(String s) throws IOException
68        {
69           // this.sendServer("mkdir "+s+"\n");
70           issueCommandCheck("mkdir " + s);
71        }
72  
73        /*** Ensure directory s exists - Create a new directory named s if it does not already exist */
74        public void endir(String s) throws IOException
75        {
76           try
77           {
78              mkdir(s);
79           }
80           catch (FtpProtocolException fpe)
81           {
82              if (fpe.getMessage().indexOf("521") == -1) //ignore this one - error 521 = directory exists
83              {
84                 throw fpe;
85              }
86           }
87        }
88  
89        /***
90         * Returns the URL of the given file in the given directory
91         */
92        public String getUrl(String directory, String filename) throws IOException
93        {
94           return "ftp://"+server+":"+port+directory+"/"+filename;
95        }
96     
97        /***
98         * Returns the URL of the given file in the current directory
99         */
100       public String getUrl(String filename) throws IOException
101       {
102          //work out where it is
103          return "ftp://"+server+":"+port+currentDir()+"/"+filename;
104       }
105 
106       /*** Delete the specified directory from the ftp file system */
107       public void rmdir(String s) throws IOException {
108          issueCommandCheck("RMD " + s);
109       }
110 
111       /*** Delete the file s from the ftp file system */
112       public void delete(String s) throws IOException {
113          issueCommandCheck("DELE " + s);
114       }
115 
116       /*** Get the name of the present working directory on the ftp file system */
117       public String currentDir() throws IOException
118       {
119          //this.sendServer("PWD");
120          issueCommandCheck("PWD");
121 //         StringBuffer result = new StringBuffer();
122 //         for (Enumeration e = serverResponse.elements(); e.hasMoreElements();) {
123 //            result.append((String) e.nextElement());
124 //         }
125 //         return result.toString();
126          String response = getResponseString();
127          return response.substring(response.indexOf('"'), response.lastIndexOf('"'));
128       }
129 
130       /*** Move up a directory (there is a command for this is 1.4, but not 1.3 */
131       public void cdup() throws IOException {
132          issueCommandCheck("CD .. ");
133       }
134 
135       /*** Move to given path.  Path may include filename, so should end up in
136        * that directory */
137       public void cdPath(String targetPath) {
138          throw new UnsupportedOperationException();
139       }
140       
141       // all client commands are sent through here
142       public int issueCommand(String cmd) throws IOException
143       {
144          org.astrogrid.log.Log.trace("FTP>"+cmd);
145          return super.issueCommand(cmd);
146       }
147 
148       public int readServerResponse() throws IOException
149       {
150          int result = super.readServerResponse();
151          for (Enumeration e = serverResponse.elements() ; e.hasMoreElements() ;)
152          {
153             org.astrogrid.log.Log.trace("FTP<"+e.nextElement());
154          }
155          return result;
156 
157       }
158 
159       public String toString()
160       {
161          return "Sun-derived FTP Client to "+server+":"+port;
162       }
163       
164    }
165 
166    /***
167     * Construct myspace client using given endpoint, which is a complete location, eg
168     * ftp://ftp.roe.ac.uk/pub/astrogrid
169     */
170    public FtpStore(User anOperator, URL ftpEndPoint) throws IOException
171    {
172       super(anOperator);
173       this.endpoint = ftpEndPoint;
174       server = ftpEndPoint.getHost();
175       port = ftpEndPoint.getPort();
176       if (port == -1) { port = DEFAULT_PORT; }
177       //hmmm @todo rootDir = url.getPath();
178    }
179 
180    /***
181     * Construct myspace client using given Agsl
182     */
183    public FtpStore(User anOperator, Agsl agsl) throws IOException
184    {
185       this(anOperator, new URL(agsl.getEndpoint()));
186    }
187 
188    /***
189     * Returns the endpoint
190     */
191    public Agsl getEndpoint() {
192       return new Agsl(endpoint);
193    }
194    
195    /***
196     * Connect to server, get authorised and move to the directory to be used
197     * for temporary publications
198     */
199    public void connect() throws IOException
200    {
201       org.astrogrid.log.Log.trace("Connecting to "+this+"...");
202 
203       try
204       {
205          ftpConnection = new FullFtpClient(server, port);
206          ftpConnection.login(getOperator().getUserId(), getOperator().getAccount());  //should be id & email
207          ftpConnection.binary();
208          // ftpConnection.endir("myspace");  //ensure directory myspace exists
209          ftpConnection.cd(rootDir);
210          org.astrogrid.log.Log.trace("...logged on to "+ftpConnection /* not in 1.3 +" running "+ftpConnection.system() **/ +"...");
211       }
212       catch (IOException ioe)
213       {
214          IOException nioe = new IOException(ioe+" ("+ftpConnection.getResponseString()+")");
215          nioe.setStackTrace(ioe.getStackTrace());
216          ftpConnection = null;
217          throw nioe;
218       }
219    }
220 
221    /***
222     * Disconnects from server, translating all faults into IOExceptions
223     */
224    public void disconnect() throws IOException
225    {
226       ftpConnection.closeServer();
227       ftpConnection = null;
228    }
229 
230    /*** For debug, returns server & port */
231    public String toString()
232    {
233       return this.getClass()+" "+server+":"+port;
234    }
235    /***
236     * Copies given stream to server; subdir specifies the subdirectory the
237     * file will be placed in.  That subdirectory will be created if it does
238     * not already exist.
239     * Returns the URL of the file on the server
240     */
241    public String pushStream(String targetPath, InputStream source, boolean append) throws IOException
242    {
243       assert ftpConnection != null : "Trying to publish before connecting. Call connect() before publicise(...)";
244 
245       org.astrogrid.log.Log.trace("Publicise: Copying '"+source+"' to '"+server+"' as '"+targetPath+"'...");
246 
247       ftpConnection.cdPath(targetPath);
248       String filename = new File(targetPath).getName();
249 
250       OutputStream remoteOut;
251       if (append) {
252          remoteOut = ftpConnection.append(filename);
253       } else {
254          remoteOut = ftpConnection.put(filename);
255       }
256 
257       Piper.bufferedPipe(source, remoteOut);
258       remoteOut.close();
259       source.close();
260       
261       return ftpConnection.getUrl(ftpConnection.currentDir(), filename);
262    }
263 
264    /***
265     * Publishes the given local file to the server (with the same name)
266     * Returns the URL of the file on the server
267     */
268    public String pushFile(String filename) throws IOException
269    {
270       return pushStream(filename, new FileInputStream(filename), false);
271    }
272 
273    /***
274     * Gets the file identified by the remote string (this might be a url)
275     * and copy it to the local filename.  If possible, it should only do this
276     * if required - ie if poss it should do some sort of time/date or
277     * checksum comparison.  Returns full path to local file
278     */
279    public String updateFromServer(String remoteUrl, String localDir) throws IOException
280    {
281       org.astrogrid.log.Log.affirm(localDir.endsWith("/"), "'"+localDir+"' should terminate with a /");
282 
283       //we assume we are in the ordinary login directory.  The filename will
284       // be preceeded by the unique id directory.
285 
286       //get *name* of remote file
287       int fni = remoteUrl.lastIndexOf('/');
288       String filename = remoteUrl.substring(fni+1);
289 
290       //get previous /<something>/ bit
291       int pdi = remoteUrl.lastIndexOf('/',fni-1);
292       String dir = remoteUrl.substring(pdi+1, fni);
293 
294       org.astrogrid.log.Log.trace("Update: Copying '"+remoteUrl+"' to '"+localDir+"'...");
295 
296       try
297       {
298          ftpConnection.cd(dir);
299          InputStream remoteIn = new BufferedInputStream(ftpConnection.get(filename));
300          OutputStream localOut = new BufferedOutputStream(new FileOutputStream(localDir+filename));
301 
302          //copy
303          int i = 0;
304          while ((i = remoteIn.read()) != -1)
305          {
306             localOut.write((byte) i);
307          }
308          remoteIn.close();
309          localOut.close();
310 
311          ftpConnection.cdup();
312          return localDir+filename;
313       }
314       catch (Exception e)
315       {
316          IOException ioe = new IOException(e+", getting '"+filename+"' from "+this);
317          //ioe.setStackTrace(e.getStackTrace());  //java v1.4+
318          ioe.fillInStackTrace(); //java v1.3
319          throw ioe;
320       }
321    }
322 
323    
324    /***
325     * Returns a tree representation of the files that match the expression
326     */
327    public StoreFile getFiles(String filter) throws IOException {
328       
329       throw new UnsupportedOperationException();
330       /*
331       //@todo
332       //oh ye gods.  OK I shall assume only one FTP server is searched (ie this one) and just return a list of names
333       BufferedReader reader = new BufferedReader(new InputStreamReader(ftpConnection.nameList(filter)));
334    
335       Vector files = new Vector();
336       
337       String line = "";
338       while (line != null)
339       {
340          line = reader.readLine();
341          if (line != null) files.add(line);
342       }
343       
344       Vector servers = new Vector();
345       servers.add(files);
346 
347       return null;
348        */
349    }
350    
351    /***
352     * Returns a list of the files that match the expression
353     */
354    public StoreFile[] getChildren(StoreFile folder, String filter) throws IOException {
355       
356       throw new UnsupportedOperationException();
357       //@todo
358    }
359    
360    /***
361     * Returns the parent of the given file
362     */
363    public StoreFile getParent(StoreFile child) throws IOException {
364       
365       throw new UnsupportedOperationException();
366       //@todo
367    }
368 
369    /***
370     * Returns the file corresponding to the path
371     */
372    public StoreFile getFile(String path) throws IOException {
373       
374       throw new UnsupportedOperationException();
375       //@todo
376    }
377 
378 
379    
380    /***
381     * Streaming output - returns a stream that can be used to output to the given
382     * location
383     */
384    public OutputStream putStream(String targetPath, boolean append) throws IOException {
385       ftpConnection.cdPath(targetPath);
386       if (append) {
387          return ftpConnection.append(new File(targetPath).getName());
388       }
389       else {
390          return ftpConnection.put(new File(targetPath).getName());
391       }
392    }
393    
394    /***
395     * Gets a file's contents as a stream
396     */
397    public InputStream getStream(String sourcePath) throws IOException {
398       return getUrl(sourcePath).openStream();
399    }
400    
401    /***
402     * Create a container
403     */
404    public void newFolder(String targetPath) throws IOException {
405       ftpConnection.cdPath(new File(targetPath).getParent());
406       ftpConnection.mkdir(new File(targetPath).getName());
407    }
408    
409    /***
410     * Delete a file
411     */
412    public void delete(String deletePath) throws IOException {
413       ftpConnection.delete(deletePath);
414    }
415    
416    /***
417     * Gets the url to stream
418     */
419    public URL getUrl(String sourcePath) throws IOException {
420       ftpConnection.cdPath(sourcePath);
421       return new URL(ftpConnection.getUrl(new File(sourcePath).getName()));
422    }
423 
424    
425 }