KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > avalon > repository > util > LoaderUtils


1 /*
2  * Copyright 2004 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
18 package org.apache.avalon.repository.util;
19
20
21 import java.io.File JavaDoc ;
22 import java.io.FileOutputStream JavaDoc ;
23 import java.io.InputStream JavaDoc ;
24 import java.io.IOException JavaDoc ;
25 import java.io.OutputStream JavaDoc ;
26
27 import java.net.HttpURLConnection JavaDoc ;
28 import java.net.URL JavaDoc ;
29 import java.net.URLConnection JavaDoc ;
30
31 import org.apache.avalon.repository.Artifact;
32 import org.apache.avalon.repository.RepositoryException;
33
34
35 /**
36  * Utility class supporting downloading of resources based on
37  * artifact references.
38  *
39  * @author <a HREF="mailto:dev@avalon.apache.org">Avalon Development Team</a>
40  * @version $Revision: 1.7 $
41  */

42 public class LoaderUtils
43 {
44      private boolean m_online;
45
46      public LoaderUtils( boolean online )
47      {
48          m_online = online;
49      }
50
51     /**
52      * Attempts to download and cache a remote artifact trying a set of remote
53      * repositories. The operation is not fail fast and so it keeps trying if
54      * the first repository does not have the artifact in question.
55      *
56      * @param artifact the artifact to retrieve and cache
57      * @param repositories the remote repositories to try to download from
58      * @param root the root cache directory
59      * @param timestamping whether to check the modified timestamp on the
60      * <code>destinationFile</code> against the remote <code>source</code>
61      * @return URL a url referencing the local resource
62      */

63     public URL JavaDoc getResource( Artifact artifact,
64         String JavaDoc [] repositories, File JavaDoc root, boolean timestamping )
65         throws RepositoryException
66     {
67         Exception JavaDoc cause = null;
68
69         File JavaDoc destination = new File JavaDoc( root, artifact.getPath() );
70
71         if( !m_online )
72         {
73             if( destination.exists() )
74             {
75                 return getURL( destination );
76             }
77             else
78             {
79                 final String JavaDoc error =
80                   "Artifact [" + artifact
81                   + "] does not exist in local cache.";
82                 throw new RepositoryException( error );
83             }
84         }
85
86         //
87
// continue with remote repository evaluation
88
//
89

90         for ( int i = 0; i < repositories.length; i++ )
91         {
92             try
93             {
94                 String JavaDoc url = artifact.getURL( repositories[i] ) ;
95                 return getResource( url, destination, timestamping ) ;
96             }
97             catch ( Exception JavaDoc e )
98             {
99                 cause = e ;
100             }
101         }
102
103         if( destination.exists() ) return getURL( destination );
104         
105         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
106         buffer.append(
107           "Failed to download artifact to local cache file "
108           + destination.getAbsolutePath()
109           + " from hosts: " );
110         for( int i=0; i<repositories.length; i++ )
111         {
112             buffer.append( "\n " + repositories[i] );
113         }
114         throw new RepositoryException( buffer.toString(), cause );
115     }
116
117     /**
118      * Attempts to download and cache a remote artifact trying a set of remote
119      * repositories. The operation is not fail fast and so it keeps trying if
120      * the first repository does not have the artifact in question.
121      *
122      * @param artifact the artifact to retrieve and cache
123      * @param mime the mime type
124      * @param repositories the remote repositories to try to download from
125      * @param root the root cache directory
126      * @param timestamping whether to check the modified timestamp on the
127      * <code>destinationFile</code> against the remote <code>source</code>
128      * @return URL a url referencing the local resource
129      */

130     public URL JavaDoc getResource( Artifact artifact, String JavaDoc mime,
131         String JavaDoc [] repositories, File JavaDoc root, boolean timestamping )
132         throws RepositoryException
133     {
134         if( null == artifact )
135           throw new NullPointerException JavaDoc( "artifact" );
136
137         if( null == mime )
138           throw new NullPointerException JavaDoc( "mime" );
139
140         if( null == root )
141           throw new NullPointerException JavaDoc( "root" );
142
143         if( null == repositories )
144           throw new NullPointerException JavaDoc( "repositories" );
145
146         Exception JavaDoc cause = null;
147
148         File JavaDoc destination =
149           new File JavaDoc( root, artifact.getPath() + "." + mime );
150         
151         if( !m_online )
152         {
153             if( destination.exists() )
154             {
155                 return getURL( destination );
156             }
157             else
158             {
159                 final String JavaDoc error =
160                   "Artifact ["
161                   + artifact.getPath() + "." + mime
162                   + "] does not exist in local cache.";
163                 throw new RepositoryException( error );
164             }
165         }
166
167         //
168
// evaluate remote repositories
169
//
170

171         for ( int i = 0; i < repositories.length; i++ )
172         {
173             try
174             {
175                 String JavaDoc url = artifact.getURL( repositories[i] ) + "." + mime;
176                 return getResource( url, destination, timestamping ) ;
177             }
178             catch ( Exception JavaDoc e )
179             {
180                 cause = e ;
181             }
182         }
183
184         if( destination.exists() ) return getURL( destination );
185         
186         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
187         buffer.append(
188           "Failed to download mime artifact to local cache file "
189           + destination.getAbsolutePath()
190           + " from hosts: " );
191         for( int i=0; i<repositories.length; i++ )
192         {
193             buffer.append( "\n " + repositories[i] );
194         }
195         throw new RepositoryException( buffer.toString(), cause );
196     }
197     
198     /**
199      * Retrieve a remote file.
200      *
201      * @param url the of the file to retrieve
202      * @param destination where to store it
203      * @param timestamping whether to check the modified timestamp on the
204      * <code>destinationFile</code> against the remote <code>source</code>
205      * @return URL a url referencing the local resource
206      */

207     public URL JavaDoc getResource(
208       String JavaDoc url, File JavaDoc destination, boolean timestamping )
209       throws Exception JavaDoc
210     {
211
212         boolean update = destination.exists();
213         long remoteTimestamp = 0; // remote
214

215         //
216
// if timestamp is enabled and the destination file exists and
217
// the source is a file - then do a quick check using native File
218
// last modification dates to see if anything needs to be done
219
//
220

221         if( timestamping && destination.exists() && url.startsWith( "file:" ) )
222         {
223             try
224             {
225                 URL JavaDoc sourceFileUrl = new URL JavaDoc( url );
226                 String JavaDoc sourcePath = sourceFileUrl.getPath();
227                 File JavaDoc sourceFile = new File JavaDoc( sourcePath );
228                 if( destination.lastModified() >= sourceFile.lastModified() )
229                 {
230                     return destination.toURL();
231                 }
232                 else
233                 {
234                     //
235
// set the remote tamestamp here because the pricision
236
// for a file last modification date is higher then the
237
// connection last modification date
238
//
239

240                     remoteTimestamp = sourceFile.lastModified();
241                 }
242             }
243             catch( Throwable JavaDoc e )
244             {
245                 e.printStackTrace();
246             }
247         }
248
249         if( !m_online )
250         {
251              if( destination.exists() )
252              {
253                  return getURL( destination );
254              }
255              else
256              {
257                  final String JavaDoc error =
258                    "Cannot retrieve url [" + url + "] while disconnected.";
259                  throw new RepositoryException( error );
260              }
261         }
262         else
263         {
264             if( destination.exists() && !isSnapshot( destination ) )
265             {
266                 return getURL( destination );
267             }
268         }
269
270         //
271
// otherwise continue with classic processing
272
//
273

274         URL JavaDoc source = null ;
275         String JavaDoc username = null ;
276         String JavaDoc password = null ;
277
278         // We want to be able to deal with Basic Auth where the username
279
// and password are part of the URL. An example of the URL string
280
// we would like to be able to parse is like the following:
281
//
282
// http://username:password@repository.mycompany.com
283

284         int atIdx = url.indexOf( "@" ) ;
285         if ( atIdx > 0 )
286         {
287             String JavaDoc s = url.substring( 7, atIdx ) ;
288             int colon = s.indexOf( ":" ) ;
289             username = s.substring( 0, colon ) ;
290             password = s.substring( colon + 1 ) ;
291             source = new URL JavaDoc( "http://" + url.substring( atIdx + 1 ) ) ;
292         }
293         else
294         {
295             source = new URL JavaDoc( url ) ;
296         }
297
298         //set the timestamp to the file date.
299
long timestamp = 0 ;
300         boolean hasTimestamp = false ;
301         if ( timestamping && destination.exists() )
302         {
303             timestamp = destination.lastModified() ;
304             hasTimestamp = true ;
305         }
306
307         //set up the URL connection
308
URLConnection JavaDoc connection = source.openConnection() ;
309
310         //modify the headers
311
//NB: things like user authentication could go in here too.
312

313         if ( timestamping && hasTimestamp )
314         {
315             connection.setIfModifiedSince( timestamp ) ;
316         }
317
318         //connect to the remote site (may take some time)
319

320         connection.connect() ;
321
322         //next test for a 304 result (HTTP only)
323

324         if ( connection instanceof HttpURLConnection JavaDoc )
325         {
326             HttpURLConnection JavaDoc httpConnection =
327               ( HttpURLConnection JavaDoc ) connection ;
328             
329             if ( httpConnection.getResponseCode() ==
330               HttpURLConnection.HTTP_NOT_MODIFIED )
331             {
332                 return destination.toURL() ;
333             }
334             
335             // test for 401 result (HTTP only)
336
if ( httpConnection.getResponseCode() ==
337                     HttpURLConnection.HTTP_UNAUTHORIZED )
338             {
339                 throw new Exception JavaDoc( "Not authorized." ) ;
340             }
341         }
342
343         // REVISIT: at this point even non HTTP connections may support the
344
// if-modified-since behaviour - we just check the date of the
345
// content and skip the write if it is not newer.
346
// Some protocols (FTP) dont include dates, of course.
347

348         InputStream JavaDoc in = null ;
349         for ( int ii = 0; ii < 3; ii++ )
350         {
351             try
352             {
353                 in = connection.getInputStream() ;
354                 break ;
355             }
356             catch ( IOException JavaDoc ex )
357             {
358                 // do nothing
359
}
360         }
361         if ( in == null )
362         {
363             final String JavaDoc error =
364               "Connection returned a null input stream: " + url ;
365             throw new IOException JavaDoc( error ) ;
366         }
367
368         File JavaDoc parent = destination.getParentFile() ;
369         parent.mkdirs() ;
370
371         File JavaDoc tempFile = File.createTempFile( "~avalon", ".tmp", parent );
372         tempFile.deleteOnExit(); // safety harness in case we abort abnormally
373
// like a Ctrl-C.
374

375         FileOutputStream JavaDoc tempOut = new FileOutputStream JavaDoc( tempFile );
376         String JavaDoc title;
377         if( update )
378         {
379             title = "Update from: [" + source + "] ";
380         }
381         else
382         {
383             title = "Download from: [" + source + "] ";
384         }
385         copyStream( in, tempOut, true, title );
386
387         // An atomic operation and no risk of a corrupted
388
// artifact content.
389

390         tempFile.renameTo( destination );
391         
392         // if (and only if) the use file time option is set, then the
393
// saved file now has its timestamp set to that of the downloaded
394
// file
395

396         if ( timestamping )
397         {
398             if( remoteTimestamp == 0 )
399             {
400                 remoteTimestamp = connection.getLastModified() ;
401             }
402
403             if( remoteTimestamp < 0 )
404             {
405                 destination.setLastModified( System.currentTimeMillis() ) ;
406             }
407             else
408             {
409                 destination.setLastModified( remoteTimestamp ) ;
410             }
411         }
412         return destination.toURL();
413     }
414
415     private static boolean isSnapshot( File JavaDoc file )
416     {
417         return file.getName().endsWith( "SNAPSHOT" );
418     }
419
420     private static URL JavaDoc getURL( File JavaDoc file ) throws RepositoryException
421     {
422         try
423         {
424             return file.toURL();
425         }
426         catch( Throwable JavaDoc e )
427         {
428             final String JavaDoc error =
429               "Internal error while attempting to create a url from the file: "
430               + file;
431             throw new RepositoryException( error, e );
432         }
433     }
434     
435     private static void copyStream(
436       InputStream JavaDoc src, OutputStream JavaDoc dest, boolean closeStreams,
437       String JavaDoc title )
438       throws IOException JavaDoc
439     {
440         boolean progress = title != null;
441         byte[] buffer = new byte[100 * 1024] ;
442         int length ;
443         if( title != null )
444             System.out.println( title );
445         try
446         {
447             while ( ( length = src.read( buffer ) ) >= 0 )
448             {
449                 dest.write( buffer, 0, length ) ;
450                 if( progress )
451                     System.out.print( "." ) ;
452             }
453         }
454         finally
455         {
456             if( closeStreams )
457             {
458                 if( src != null )
459                     src.close();
460                 if( dest != null )
461                     dest.close();
462             }
463             if( progress )
464                 System.out.println( "" ) ;
465         }
466     }
467 }
468
Popular Tags