KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > excalibur > source > impl > FTPSource


1 /*
2  * Copyright 2002-2004 The Apache Software Foundation
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12  * implied.
13  *
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17 package org.apache.excalibur.source.impl;
18
19 import java.io.ByteArrayOutputStream JavaDoc;
20 import java.io.FileNotFoundException JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.OutputStream JavaDoc;
23 import java.net.URL JavaDoc;
24 import java.util.Map JavaDoc;
25
26 import org.apache.excalibur.source.ModifiableSource;
27 import org.apache.excalibur.source.SourceException;
28 import org.apache.excalibur.source.SourceNotFoundException;
29 import org.apache.excalibur.source.SourceParameters;
30 import org.apache.excalibur.source.SourceResolver;
31 import org.apache.excalibur.source.SourceUtil;
32
33 import sun.net.ftp.FtpClient;
34
35 /**
36  * Source implementation for the File Transfer Protocol.
37  *
38  * @author <a HREF="mailto:dev@avalon.apache.org">Avalon Development Team</a>
39  */

40 public class FTPSource extends URLSource implements ModifiableSource
41 {
42     private boolean m_isAscii;
43     
44     public FTPSource()
45     {
46         super();
47     }
48
49     /**
50      * Initialize a new object from a <code>URL</code>.
51      * @param parameters This is optional
52      */

53     public void init(final URL JavaDoc url, final Map JavaDoc parameters) throws IOException JavaDoc
54     {
55         final String JavaDoc systemId = url.toExternalForm();
56         setSystemId(systemId);
57         setScheme(SourceUtil.getScheme(systemId));
58
59         m_url = url;
60         m_isAscii = false;
61
62         if (parameters != null)
63         {
64             m_parameters = (SourceParameters) parameters.get(SourceResolver.URI_PARAMETERS);
65             final String JavaDoc method = (String JavaDoc) parameters.get(SourceResolver.METHOD);
66
67             if ("ASCII".equalsIgnoreCase(method))
68             {
69                 m_isAscii = true;
70             }
71         }
72     }
73
74     /**
75      * Can the data sent to an <code>OutputStream</code> returned by
76      * {@link #getOutputStream()} be cancelled ?
77      *
78      * @return <code>true</code> if the stream can be cancelled
79      */

80     public boolean canCancel( final OutputStream JavaDoc stream )
81     {
82         if (stream instanceof FTPSourceOutputStream)
83         {
84             FTPSourceOutputStream fsos = (FTPSourceOutputStream) stream;
85             if ( fsos.getSource() == this )
86             {
87                 return fsos.canCancel();
88             }
89         }
90
91         throw new IllegalArgumentException JavaDoc( "The stream is not associated to this source" );
92     }
93
94     /**
95      * Cancel the data sent to an <code>OutputStream</code> returned by
96      * {@link #getOutputStream()}.
97      * <p>
98      * After cancel, the stream should not be used.
99      */

100     public void cancel( final OutputStream JavaDoc stream ) throws IOException JavaDoc
101     {
102         if (stream instanceof FTPSourceOutputStream)
103         {
104             FTPSourceOutputStream fsos = (FTPSourceOutputStream) stream;
105             if ( fsos.getSource() == this )
106             {
107                 try
108                 {
109                     fsos.cancel();
110                 }
111                 catch ( Exception JavaDoc e )
112                 {
113                     throw new SourceException( "Exception during cancel.", e );
114                 }
115                 return;
116             }
117         }
118
119         throw new IllegalArgumentException JavaDoc( "The stream is not associated to this source" );
120     }
121
122     /**
123      * Delete the source.
124      */

125     public void delete() throws SourceException
126     {
127         EnhancedFtpClient ftpClient = null;
128         try
129         {
130             ftpClient = getFtpClient();
131             final String JavaDoc relativePath = m_url.getPath().substring( 1 );
132             ftpClient.delete( relativePath );
133         }
134         catch ( IOException JavaDoc e )
135         {
136             if ( e instanceof FileNotFoundException JavaDoc )
137             {
138                 throw new SourceNotFoundException( e.getMessage() );
139             }
140             else
141             {
142                 final String JavaDoc message =
143                     "Failure during delete";
144                 throw new SourceException( message, e );
145             }
146         }
147         finally
148         {
149             if ( ftpClient != null )
150             {
151                 try
152                 {
153                     ftpClient.closeServer();
154                 }
155                 catch ( IOException JavaDoc e ) {}
156             }
157         }
158     }
159
160     /**
161      * Get the last modification date and content length of the source.
162      * Any exceptions are ignored.
163      */

164     protected void getInfos()
165     {
166         // exists will be set below depending on the m_url type
167
m_exists = false;
168         try
169         {
170             if (null == m_connection)
171             {
172                 m_connection = m_url.openConnection();
173                 String JavaDoc userInfo = m_url.getUserInfo();
174             }
175             setLastModified(m_connection.getLastModified());
176             setContentLength(m_connection.getContentLength());
177             // getting the content type here seems to screw up=20
178
// the InputStream on the URLConnection.
179
// m_mimeType = m_connection.getContentType();
180
m_mimeType = null;
181             m_exists = true;
182         }
183         catch (IOException JavaDoc ignore)
184         {
185             setContentLength(-1);
186             setLastModified(0);
187         }
188     }
189
190     /**
191      * Return an {@link OutputStream} to write to.
192      */

193     public OutputStream JavaDoc getOutputStream() throws IOException JavaDoc
194     {
195         return new FTPSourceOutputStream( this );
196     }
197     
198     /**
199      * Creates an FtpClient and logs in the current user.
200      */

201     private final EnhancedFtpClient getFtpClient()
202         throws IOException JavaDoc
203     {
204         final EnhancedFtpClient ftpClient =
205             new EnhancedFtpClient( m_url.getHost() );
206         ftpClient.login( getUser(), getPassword() );
207         return ftpClient;
208     }
209     
210     /**
211      * @return the user part of the user info string,
212      * <code>null</code> if there is no user info.
213      */

214     private final String JavaDoc getUser()
215     {
216         final String JavaDoc userInfo = m_url.getUserInfo();
217         if ( userInfo != null )
218         {
219             int index = userInfo.indexOf( ':' );
220             if ( index != -1 )
221             {
222                 return userInfo.substring( 0, index );
223             }
224         }
225         return null;
226     }
227     
228     /**
229      * @return the password part of the user info string,
230      * <code>null</code> if there is no user info.
231      */

232     private final String JavaDoc getPassword()
233     {
234         final String JavaDoc userInfo = m_url.getUserInfo();
235         if ( userInfo != null )
236         {
237             int index = userInfo.indexOf( ':' );
238             if ( index != -1 && userInfo.length() > index + 1 )
239             {
240                 return userInfo.substring( index + 1 );
241             }
242         }
243         return null;
244     }
245     
246     /**
247      * Need to extend FtpClient in order to get to protected issueCommand
248      * and implement additional functionality.
249      */

250     private static class EnhancedFtpClient extends FtpClient
251     {
252         
253         private EnhancedFtpClient( String JavaDoc host ) throws IOException JavaDoc
254         {
255             super( host );
256         }
257         
258         void delete( final String JavaDoc path ) throws IOException JavaDoc
259         {
260             issueCommand( "DELE " + path );
261         }
262         
263         /**
264          * Create a directory in the current working directory.
265          */

266         void mkdir( final String JavaDoc directoryName ) throws IOException JavaDoc
267         {
268             issueCommand( "MKD " + directoryName );
269         }
270         
271         /**
272          * Create all directories along a directory path if they
273          * do not already exist.
274          *
275          * The algorithm traverses the directory tree in reversed
276          * direction. cd'ing first to the deepest level
277          * and if that directory doesn't exist try cd'ing to its
278          * parent from where it can be created.
279          *
280          * NOTE: after completion the current working directory
281          * will be the directory identified by directoryPath.
282          */

283         void mkdirs( final String JavaDoc directoryPath ) throws IOException JavaDoc
284         {
285             try
286             {
287                 cd( directoryPath );
288             }
289             catch ( FileNotFoundException JavaDoc e )
290             {
291                 // doesn't exist, create it
292
String JavaDoc directoryName = null;
293                 final int index = directoryPath.lastIndexOf( '/' );
294                 if ( index != -1 )
295                 {
296                     final String JavaDoc parentDirectoryPath =
297                         directoryPath.substring( 0, index );
298                     directoryName = directoryPath.substring( index + 1 );
299                     mkdirs( parentDirectoryPath );
300                 }
301                 else
302                 {
303                     directoryName = directoryPath;
304                 }
305                 mkdir( directoryName );
306                 cd( directoryName );
307             }
308         }
309                     
310     }
311     
312     /**
313      * Buffers the output in a byte array and only writes to the remote
314      * FTP location at closing time.
315      */

316     private static class FTPSourceOutputStream extends ByteArrayOutputStream JavaDoc
317     {
318         private final FTPSource m_source;
319         private boolean m_isClosed = false;
320         
321         FTPSourceOutputStream( final FTPSource source )
322         {
323             super( 8192 );
324             m_source = source;
325         }
326         
327         public void close() throws IOException JavaDoc
328         {
329             if ( !m_isClosed )
330             {
331                 EnhancedFtpClient ftpClient = null;
332                 OutputStream JavaDoc out = null;
333                 try
334                 {
335                     ftpClient = m_source.getFtpClient();
336                     if (m_source.m_isAscii) {
337                         ftpClient.ascii();
338                     } else {
339                         ftpClient.binary();
340                     }
341                     String JavaDoc parentPath = null;
342                     String JavaDoc fileName = null;
343                     final String JavaDoc relativePath = m_source.m_url.getPath().substring( 1 );
344                     final int index = relativePath.lastIndexOf( '/' );
345                     if ( index != -1 )
346                     {
347                         parentPath = relativePath.substring( 0, index );
348                         fileName = relativePath.substring( index + 1 );
349                         ftpClient.mkdirs( parentPath );
350                     }
351                     else
352                     {
353                         fileName = relativePath;
354                     }
355                     out = ftpClient.put( fileName );
356                     final byte[] bytes = toByteArray();
357                     out.write( bytes );
358                 }
359                 finally
360                 {
361                     if ( out != null )
362                     {
363                         try
364                         {
365                             out.close();
366                         }
367                         catch ( IOException JavaDoc e ) {}
368                     }
369                     if ( ftpClient != null )
370                     {
371                         try
372                         {
373                             ftpClient.closeServer();
374                         }
375                         catch ( IOException JavaDoc e ) {}
376                     }
377                     m_isClosed = true;
378                 }
379             }
380         }
381         
382         boolean canCancel()
383         {
384             return !m_isClosed;
385         }
386
387         void cancel() throws Exception JavaDoc
388         {
389             if ( m_isClosed )
390             {
391                 final String JavaDoc message =
392                     "Cannot cancel: outputstrem is already closed";
393                 throw new IllegalStateException JavaDoc( message );
394             }
395             m_isClosed = true;
396         }
397         
398         FTPSource getSource()
399         {
400             return m_source;
401         }
402         
403     }
404
405 }
406
Popular Tags