]> source.dussan.org Git - archiva.git/blob
a22fdb872c9b479a0dbb698c12d4da9eeaad9f0e
[archiva.git] /
1 package org.apache.maven.archiva.proxy;
2
3 /*
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements.  See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership.  The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License"); you may not use this file except in compliance
10  * with the License.  You may obtain a copy of the License at
11  *
12  *   http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  * KIND, either express or implied.  See the License for the
18  * specific language governing permissions and limitations
19  * under the License.
20  */
21
22 import org.apache.commons.io.FileUtils;
23 import org.apache.commons.io.IOUtils;
24 import org.apache.maven.archiva.common.artifact.builder.BuilderException;
25 import org.apache.maven.archiva.common.artifact.builder.LayoutArtifactBuilder;
26 import org.apache.maven.artifact.Artifact;
27 import org.apache.maven.artifact.factory.ArtifactFactory;
28 import org.apache.maven.artifact.repository.ArtifactRepository;
29 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
30 import org.apache.maven.artifact.repository.metadata.Metadata;
31 import org.apache.maven.artifact.repository.metadata.Versioning;
32 import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
33 import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer;
34 import org.apache.maven.model.DistributionManagement;
35 import org.apache.maven.model.Model;
36 import org.apache.maven.model.Relocation;
37 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
38 import org.apache.maven.wagon.ConnectionException;
39 import org.apache.maven.wagon.ResourceDoesNotExistException;
40 import org.apache.maven.wagon.TransferFailedException;
41 import org.apache.maven.wagon.Wagon;
42 import org.apache.maven.wagon.authentication.AuthenticationException;
43 import org.apache.maven.wagon.authorization.AuthorizationException;
44 import org.apache.maven.wagon.observers.ChecksumObserver;
45 import org.apache.maven.wagon.proxy.ProxyInfo;
46 import org.apache.maven.wagon.repository.Repository;
47 import org.codehaus.plexus.digest.DigestUtils;
48 import org.codehaus.plexus.digest.DigesterException;
49 import org.codehaus.plexus.logging.AbstractLogEnabled;
50 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
51
52 import java.io.File;
53 import java.io.FileReader;
54 import java.io.FileWriter;
55 import java.io.IOException;
56 import java.io.Reader;
57 import java.security.NoSuchAlgorithmException;
58 import java.text.DateFormat;
59 import java.text.SimpleDateFormat;
60 import java.util.Date;
61 import java.util.Iterator;
62 import java.util.LinkedHashMap;
63 import java.util.List;
64 import java.util.Locale;
65 import java.util.Map;
66 import java.util.TimeZone;
67
68 /**
69  * An implementation of the proxy handler. This class is not thread safe (the class itself is, but the wagons it uses
70  * are not) - it is declared <code>per-lookup</code> for that reason.
71  *
72  * @author <a href="mailto:brett@apache.org">Brett Porter</a>
73  * @plexus.component instantiation-strategy="per-lookup"
74  * @todo use wagonManager for cache use file:// as URL
75  * @todo this currently duplicates a lot of the wagon manager, and doesn't do things like snapshot resolution, etc.
76  * The checksum handling is inconsistent with that of the wagon manager.
77  * Should we have a more artifact based one? This will merge metadata so should behave correctly, and it is able to
78  * correct some limitations of the wagon manager (eg, it can retrieve newer SNAPSHOT files without metadata)
79  */
80 public class DefaultProxyRequestHandler
81     extends AbstractLogEnabled
82     implements ProxyRequestHandler
83 {
84     /**
85      * @plexus.requirement
86      */
87     private ArtifactFactory factory;
88     
89     /**
90      * @plexus.requirement role-hint="default"
91      * @todo use a map, and have priorities in them.
92      */
93     private LayoutArtifactBuilder defaultArtifactBuilder;
94     
95     /**
96      * @plexus.requirement role-hint="legacy"
97      */
98     private LayoutArtifactBuilder legacyArtifactBuilder;
99
100     /**
101      * @plexus.requirement role="org.apache.maven.wagon.Wagon"
102      */
103     private Map/*<String,Wagon>*/ wagons;
104
105     private static final TimeZone UTC_TIMEZONE = TimeZone.getTimeZone( "UTC" );
106
107     public File get( String path, List proxiedRepositories, ArtifactRepository managedRepository )
108         throws ProxyException, ResourceDoesNotExistException
109     {
110         return get( path, proxiedRepositories, managedRepository, null );
111     }
112
113     public File get( String path, List proxiedRepositories, ArtifactRepository managedRepository, ProxyInfo wagonProxy )
114         throws ProxyException, ResourceDoesNotExistException
115     {
116         return get( managedRepository, path, proxiedRepositories, wagonProxy, false );
117     }
118
119     public File getAlways( String path, List proxiedRepositories, ArtifactRepository managedRepository )
120         throws ProxyException, ResourceDoesNotExistException
121     {
122         return getAlways( path, proxiedRepositories, managedRepository, null );
123     }
124
125     public File getAlways( String path, List proxiedRepositories, ArtifactRepository managedRepository,
126                            ProxyInfo wagonProxy )
127         throws ResourceDoesNotExistException, ProxyException
128     {
129         return get( managedRepository, path, proxiedRepositories, wagonProxy, true );
130     }
131
132     private File get( ArtifactRepository managedRepository, String path, List proxiedRepositories, ProxyInfo wagonProxy,
133                       boolean force )
134         throws ProxyException, ResourceDoesNotExistException
135     {
136         File target = new File( managedRepository.getBasedir(), path );
137
138         if ( path.endsWith( "maven-metadata.xml" ) )
139         {
140             // Request for managed repository metadatas
141             getMetadata( path, target, proxiedRepositories, managedRepository, wagonProxy, force );
142         }
143         else
144         {
145             boolean checksum = false;
146             String checksumExtension = null;
147             String artifactPath = path;
148             if ( path.endsWith( ".md5" ) || path.endsWith( ".sha1" ) )
149             {
150                 int index = path.lastIndexOf( '.' );
151                 checksumExtension = path.substring( index + 1 );
152                 checksum = true;
153                 artifactPath = path.substring( 0, index );
154             }
155
156             String msg = "";
157
158             // Request for artifact: parse the requested path to build an Artifact.
159             Artifact artifact = null;
160             try
161             {
162                 artifact = defaultArtifactBuilder.build( artifactPath );
163                 getLogger().debug( "Artifact requested is: " + artifact );
164             }
165             catch ( BuilderException e )
166             {
167                 msg = "Failed to build artifact from path:\n\tfrom default: " + e.getMessage();
168             }
169
170             if ( artifact == null )
171             {
172                 try
173                 {
174                     artifact = legacyArtifactBuilder.build( artifactPath );
175                     getLogger().debug( "Artifact requested is: " + artifact );
176                 }
177                 catch ( BuilderException e )
178                 {
179                     getLogger().debug( msg + "\n\tfrom legacy: " + e.getMessage() );
180                 }
181             }
182
183             if ( artifact != null )
184             {
185                 applyRelocation( managedRepository, artifact, proxiedRepositories, wagonProxy, force );
186
187                 if ( !checksum )
188                 {
189                     // Build the target file name
190                     target = new File( managedRepository.getBasedir(), managedRepository.pathOf( artifact ) );
191
192                     // Get the requested artifact from proxiedRepositories
193                     getArtifactFromRepository( managedRepository, target, artifact, proxiedRepositories, wagonProxy,
194                                                force );
195                 }
196                 else
197                 {
198                     // Just adjust the filename for relocation, don't actualy get it
199                     target = new File( managedRepository.getBasedir(),
200                                        managedRepository.pathOf( artifact ) + "." + checksumExtension );
201                 }
202             }
203             else if ( !checksum )
204             {
205                 // Some other unknown file in the repository, proxy as is, unless it was a checksum
206                 if ( force || !target.exists() )
207                 {
208                     getFileFromRepository( managedRepository, target, path, proxiedRepositories, wagonProxy, force );
209                 }
210             }
211         }
212
213         if ( !target.exists() )
214         {
215             throw new ResourceDoesNotExistException( "Could not find " + path + " in any of the repositories." );
216         }
217
218         return target;
219     }
220
221     private void getFileFromRepository( ArtifactRepository managedRepository, File target, String path,
222                                         List proxiedRepositories, ProxyInfo wagonProxy, boolean force )
223         throws ProxyException, ResourceDoesNotExistException
224     {
225         for ( Iterator i = proxiedRepositories.iterator(); i.hasNext(); )
226         {
227             ProxiedArtifactRepository repository = (ProxiedArtifactRepository) i.next();
228
229             if ( !force && repository.isCachedFailure( path ) )
230             {
231                 processCachedRepositoryFailure( repository, "Cached failure found for: " + path );
232             }
233             else
234             {
235                 ArtifactRepositoryPolicy policy = repository.getRepository().getReleases();
236                 getFileFromRepository( path, repository, managedRepository.getBasedir(), wagonProxy, target, policy,
237                                        force );
238             }
239         }
240     }
241
242     private void getArtifactFromRepository( ArtifactRepository managedRepository, File target, Artifact artifact,
243                                             List proxiedRepositories, ProxyInfo wagonProxy, boolean force )
244         throws ProxyException, ResourceDoesNotExistException
245     {
246         for ( Iterator i = proxiedRepositories.iterator(); i.hasNext(); )
247         {
248             ProxiedArtifactRepository repository = (ProxiedArtifactRepository) i.next();
249             String path = repository.getRepository().getLayout().pathOf( artifact );
250
251             if ( !force && repository.isCachedFailure( path ) )
252             {
253                 processCachedRepositoryFailure( repository, "Cached failure found for: " + path );
254             }
255             else
256             {
257                 get( artifact, target, repository, managedRepository, wagonProxy, force );
258             }
259         }
260     }
261
262     private void applyRelocation( ArtifactRepository managedRepository, Artifact artifact, List proxiedRepositories,
263                                   ProxyInfo wagonProxy, boolean force )
264     {
265         Artifact pomArtifact =
266             factory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion() );
267
268         File pomFile = new File( managedRepository.getBasedir(), managedRepository.pathOf( pomArtifact ) );
269         try
270         {
271             getArtifactFromRepository( managedRepository, pomFile, pomArtifact, proxiedRepositories, wagonProxy,
272                                        force );
273         }
274         catch ( ProxyException e )
275         {
276             getLogger().warn( "Error getting POM for artifact - not relocating: " + e.getMessage() );
277             getLogger().debug( "Cause", e );
278         }
279         catch ( ResourceDoesNotExistException e )
280         {
281             getLogger().debug( "Remote POM not found for artifact - not relocating" );
282         }
283
284         if ( pomFile.exists() )
285         {
286             Model model = null;
287             try
288             {
289                 // Parse the pom and look at relocation metadata
290                 Reader reader = new FileReader( pomFile );
291                 model = new MavenXpp3Reader().read( reader );
292             }
293             catch ( IOException e )
294             {
295                 getLogger().warn( "Error reading POM for artifact - not relocating: " + e.getMessage() );
296                 getLogger().debug( "Cause", e );
297             }
298             catch ( XmlPullParserException e )
299             {
300                 getLogger().warn( "Error parsing POM for artifact - not relocating: " + e.getMessage() );
301                 getLogger().debug( "Cause", e );
302             }
303
304             if ( model != null )
305             {
306                 DistributionManagement dist;
307                 dist = model.getDistributionManagement();
308
309                 if ( dist != null )
310                 {
311                     Relocation relocation = dist.getRelocation();
312                     if ( relocation != null )
313                     {
314                         String requestedId =
315                             artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion();
316
317                         // artifact is relocated : update the artifact
318                         if ( relocation.getGroupId() != null )
319                         {
320                             artifact.setGroupId( relocation.getGroupId() );
321                         }
322                         if ( relocation.getArtifactId() != null )
323                         {
324                             artifact.setArtifactId( relocation.getArtifactId() );
325                         }
326                         if ( relocation.getVersion() != null )
327                         {
328                             artifact.setVersion( relocation.getVersion() );
329                         }
330
331                         String relocatedId =
332                             artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion();
333
334                         getLogger().debug( "Artifact " + requestedId + " has been relocated to " + relocatedId +
335                             ( relocation.getMessage() != null ? ": " + relocation.getMessage() : "" ) );
336
337                         applyRelocation( managedRepository, artifact, proxiedRepositories, wagonProxy, force );
338                     }
339                 }
340             }
341         }
342     }
343
344     private void getMetadata( String path, File target, List proxiedRepositories, ArtifactRepository managedRepository,
345                               ProxyInfo wagonProxy, boolean force )
346         throws ProxyException
347     {
348         for ( Iterator i = proxiedRepositories.iterator(); i.hasNext(); )
349         {
350             ProxiedArtifactRepository repository = (ProxiedArtifactRepository) i.next();
351             File metadataFile = new File( target.getParentFile(), ".metadata-" + repository.getRepository().getId() );
352
353             ArtifactRepositoryPolicy policy = repository.getRepository().getReleases();
354
355             // if it is snapshot metadata, use a different policy
356             if ( path.endsWith( "-SNAPSHOT/maven-metadata.xml" ) )
357             {
358                 policy = repository.getRepository().getSnapshots();
359             }
360
361             if ( force || !metadataFile.exists() || isOutOfDate( policy, metadataFile ) )
362             {
363                 getFileFromRepository( path, repository, managedRepository.getBasedir(), wagonProxy, metadataFile,
364                                        policy, force );
365
366                 mergeMetadataFiles( target, metadataFile );
367             }
368         }
369     }
370
371     private void get( Artifact artifact, File target, ProxiedArtifactRepository repository,
372                       ArtifactRepository managedRepository, ProxyInfo wagonProxy, boolean force )
373         throws ProxyException
374     {
375         ArtifactRepository artifactRepository = repository.getRepository();
376
377         // we use the release policy for tracking failures, but only check for updates on snapshots
378         // also, we don't look for updates on timestamp snapshot files, only non-unique-version ones
379         ArtifactRepositoryPolicy policy =
380             artifact.isSnapshot() ? artifactRepository.getSnapshots() : artifactRepository.getReleases();
381
382         boolean needsUpdate = false;
383         if ( artifact.getVersion().endsWith( "-SNAPSHOT" ) && isOutOfDate( policy, target ) )
384         {
385             needsUpdate = true;
386         }
387
388         if ( needsUpdate || force || !target.exists() )
389         {
390             getFileFromRepository( artifactRepository.pathOf( artifact ), repository, managedRepository.getBasedir(),
391                                    wagonProxy, target, policy, force );
392         }
393     }
394
395     private void mergeMetadataFiles( File target, File metadataFile )
396         throws ProxyException
397     {
398         MetadataXpp3Reader reader = new MetadataXpp3Reader();
399         if ( metadataFile.exists() )
400         {
401             Metadata metadata = null;
402             if ( target.exists() )
403             {
404                 FileReader fileReader = null;
405                 try
406                 {
407                     fileReader = new FileReader( target );
408                     metadata = reader.read( fileReader );
409                 }
410                 catch ( XmlPullParserException e )
411                 {
412                     throw new ProxyException( "Unable to parse existing metadata: " + e.getMessage(), e );
413                 }
414                 catch ( IOException e )
415                 {
416                     throw new ProxyException( "Unable to read existing metadata: " + e.getMessage(), e );
417                 }
418                 finally
419                 {
420                     IOUtils.closeQuietly( fileReader );
421                 }
422             }
423
424             FileReader fileReader = null;
425             boolean changed = false;
426             try
427             {
428                 fileReader = new FileReader( metadataFile );
429                 Metadata newMetadata = reader.read( fileReader );
430
431                 if ( metadata != null )
432                 {
433                     setLastUpdatedIfEmpty( newMetadata, metadataFile );
434                     setLastUpdatedIfEmpty( metadata, target );
435
436                     changed = metadata.merge( newMetadata );
437                 }
438                 else
439                 {
440                     metadata = newMetadata;
441                     changed = true;
442                 }
443             }
444             catch ( IOException e )
445             {
446                 // ignore the merged file
447                 getLogger().warn( "Unable to read new metadata: " + e.getMessage() );
448             }
449             catch ( XmlPullParserException e )
450             {
451                 // ignore the merged file
452                 getLogger().warn( "Unable to parse new metadata: " + e.getMessage() );
453             }
454             finally
455             {
456                 IOUtils.closeQuietly( fileReader );
457             }
458
459             if ( changed )
460             {
461                 FileWriter fileWriter = null;
462                 try
463                 {
464                     fileWriter = new FileWriter( target );
465                     new MetadataXpp3Writer().write( fileWriter, metadata );
466                 }
467                 catch ( IOException e )
468                 {
469                     getLogger().warn( "Unable to store new metadata: " + e.getMessage() );
470                 }
471                 finally
472                 {
473                     IOUtils.closeQuietly( fileWriter );
474                 }
475             }
476         }
477     }
478
479     private void setLastUpdatedIfEmpty( Metadata metadata, File metadataFile )
480     {
481         if ( metadata.getVersioning() == null )
482         {
483             metadata.setVersioning( new Versioning() );
484         }
485         if ( metadata.getVersioning().getLastUpdated() == null )
486         {
487             DateFormat fmt = new SimpleDateFormat( "yyyyMMddHHmmss", Locale.US );
488             fmt.setTimeZone( UTC_TIMEZONE );
489             metadata.getVersioning().setLastUpdated( fmt.format( new Date( metadataFile.lastModified() ) ) );
490         }
491     }
492
493     private void getFileFromRepository( String path, ProxiedArtifactRepository repository, String repositoryCachePath,
494                                         ProxyInfo httpProxy, File target, ArtifactRepositoryPolicy policy,
495                                         boolean force )
496         throws ProxyException
497     {
498         if ( !policy.isEnabled() )
499         {
500             getLogger().debug( "Skipping disabled repository " + repository.getName() );
501             return;
502         }
503
504         Map checksums = null;
505         Wagon wagon = null;
506
507         File temp = new File( target.getAbsolutePath() + ".tmp" );
508         temp.deleteOnExit();
509
510         boolean connected = false;
511         try
512         {
513             String protocol = repository.getRepository().getProtocol();
514             wagon = (Wagon) wagons.get( protocol );
515             if ( wagon == null )
516             {
517                 throw new ProxyException( "Unsupported remote protocol: " + protocol );
518             }
519
520             //@todo configure wagon (ssh settings, etc)
521
522             checksums = prepareChecksumListeners( wagon );
523
524             connected = connectToRepository( wagon, repository, httpProxy );
525             if ( connected )
526             {
527                 int tries = 0;
528                 boolean success;
529
530                 do
531                 {
532                     tries++;
533
534                     boolean downloaded = true;
535                     if ( force || !target.exists() )
536                     {
537                         getLogger().debug( "Retrieving " + path + " from " + repository.getName() );
538                         wagon.get( path, temp );
539                     }
540                     else
541                     {
542                         getLogger().debug( "Retrieving " + path + " from " + repository.getName() + " if updated" );
543                         downloaded = wagon.getIfNewer( path, temp, target.lastModified() );
544                     }
545
546                     if ( downloaded )
547                     {
548                         success = checkChecksum( checksums, path, wagon, repositoryCachePath );
549
550                         if ( tries > 1 && !success )
551                         {
552                             processRepositoryFailure( repository,
553                                                       "Checksum failures occurred while downloading " + path, path,
554                                                       policy );
555                             return;
556                         }
557                     }
558                     else
559                     {
560                         // getIfNewer determined we were up to date
561                         success = true;
562                     }
563                 }
564                 while ( !success );
565
566                 // temp won't exist if we called getIfNewer and it was older, but its still a successful return
567                 if ( temp.exists() )
568                 {
569                     moveTempToTarget( temp, target );
570                 }
571
572                 getLogger().debug( "Successfully downloaded" );
573             }
574             //try next repository
575         }
576         catch ( TransferFailedException e )
577         {
578             processRepositoryFailure( repository, e, path, policy );
579         }
580         catch ( AuthorizationException e )
581         {
582             processRepositoryFailure( repository, e, path, policy );
583         }
584         catch ( ResourceDoesNotExistException e )
585         {
586             // hard failure setting doesn't affect "not found".
587             getLogger().debug( "Artifact not found in repository: " + repository.getName() + ": " + e.getMessage() );
588         }
589         finally
590         {
591             temp.delete();
592
593             if ( wagon != null && checksums != null )
594             {
595                 releaseChecksumListeners( wagon, checksums );
596             }
597
598             if ( connected )
599             {
600                 disconnectWagon( wagon );
601             }
602         }
603     }
604
605     private static boolean isOutOfDate( ArtifactRepositoryPolicy policy, File target )
606     {
607         return policy != null && policy.checkOutOfDate( new Date( target.lastModified() ) );
608     }
609
610     /**
611      * Used to add checksum observers as transfer listeners to the wagonManager object
612      *
613      * @param wagon the wagonManager object to use the checksum with
614      * @return map of ChecksumObservers added into the wagonManager transfer listeners
615      */
616     private Map prepareChecksumListeners( Wagon wagon )
617     {
618         Map checksums = new LinkedHashMap();
619         try
620         {
621             ChecksumObserver checksum = new ChecksumObserver( "SHA-1" );
622             wagon.addTransferListener( checksum );
623             checksums.put( "sha1", checksum );
624
625             checksum = new ChecksumObserver( "MD5" );
626             wagon.addTransferListener( checksum );
627             checksums.put( "md5", checksum );
628         }
629         catch ( NoSuchAlgorithmException e )
630         {
631             getLogger().error( "An error occurred while preparing checksum observers: " + e.getMessage() );
632         }
633         return checksums;
634     }
635
636     private void releaseChecksumListeners( Wagon wagon, Map checksumMap )
637     {
638         for ( Iterator checksums = checksumMap.values().iterator(); checksums.hasNext(); )
639         {
640             ChecksumObserver listener = (ChecksumObserver) checksums.next();
641             wagon.removeTransferListener( listener );
642         }
643     }
644
645     private boolean connectToRepository( Wagon wagon, ProxiedArtifactRepository repository, ProxyInfo httpProxy )
646     {
647         boolean connected = false;
648         try
649         {
650             ArtifactRepository artifactRepository = repository.getRepository();
651             Repository wagonRepository = new Repository( artifactRepository.getId(), artifactRepository.getUrl() );
652             if ( repository.isUseNetworkProxy() && httpProxy != null )
653             {
654                 wagon.connect( wagonRepository, httpProxy );
655             }
656             else
657             {
658                 wagon.connect( wagonRepository );
659             }
660             connected = true;
661         }
662         catch ( ConnectionException e )
663         {
664             getLogger().info( "Could not connect to " + repository.getName() + ": " + e.getMessage() );
665         }
666         catch ( AuthenticationException e )
667         {
668             getLogger().info( "Could not connect to " + repository.getName() + ": " + e.getMessage() );
669         }
670
671         return connected;
672     }
673
674     private boolean checkChecksum( Map checksumMap, String path, Wagon wagon, String repositoryCachePath )
675         throws ProxyException
676     {
677         releaseChecksumListeners( wagon, checksumMap );
678
679         boolean correctChecksum = false;
680
681         boolean allNotFound = true;
682
683         for ( Iterator i = checksumMap.keySet().iterator(); i.hasNext() && !correctChecksum; )
684         {
685             String checksumExt = (String) i.next();
686             ChecksumObserver checksum = (ChecksumObserver) checksumMap.get( checksumExt );
687             String checksumPath = path + "." + checksumExt;
688             File checksumFile = new File( repositoryCachePath, checksumPath );
689
690             File tempChecksumFile = new File( checksumFile.getAbsolutePath() + ".tmp" );
691             tempChecksumFile.deleteOnExit();
692
693             try
694             {
695                 wagon.get( checksumPath, tempChecksumFile );
696
697                 allNotFound = false;
698
699                 String remoteChecksum = DigestUtils.cleanChecksum( FileUtils.readFileToString( tempChecksumFile, null ),
700                                                                    checksumExt.toUpperCase(),
701                                                                    path.substring( path.lastIndexOf( '/' ) + 1 ) );
702
703                 String actualChecksum = checksum.getActualChecksum();
704
705                 remoteChecksum = remoteChecksum.toUpperCase();
706
707                 if ( actualChecksum != null && remoteChecksum.equals( actualChecksum.toUpperCase() ) )
708                 {
709                     moveTempToTarget( tempChecksumFile, checksumFile );
710
711                     correctChecksum = true;
712                 }
713                 else
714                 {
715                     getLogger().warn(
716                         "The checksum '" + actualChecksum + "' did not match the remote value: " + remoteChecksum );
717                 }
718             }
719             catch ( TransferFailedException e )
720             {
721                 getLogger().warn( "An error occurred during the download of " + checksumPath + ": " + e.getMessage() );
722                 // do nothing try the next checksum
723
724                 allNotFound = false;
725             }
726             catch ( ResourceDoesNotExistException e )
727             {
728                 getLogger().debug( "The checksum did not exist: " + checksumPath + "; " + e.getMessage() );
729                 // do nothing try the next checksum
730                 // remove it if it is present locally in case there is an old incorrect one
731                 if ( checksumFile.exists() )
732                 {
733                     checksumFile.delete();
734                 }
735             }
736             catch ( AuthorizationException e )
737             {
738                 getLogger().warn( "An error occurred during the download of " + checksumPath + ": " + e.getMessage() );
739                 // do nothing try the next checksum
740
741                 allNotFound = false;
742             }
743             catch ( IOException e )
744             {
745                 getLogger().warn( "An error occurred while reading the temporary checksum file: " + e.getMessage() );
746                 // do nothing try the next checksum
747
748                 allNotFound = false;
749             }
750             catch ( DigesterException e )
751             {
752                 getLogger().warn( "The checksum was invalid: " + checksumPath + ": " + e.getMessage() );
753                 // do nothing try the next checksum
754
755                 allNotFound = false;
756             }
757             finally
758             {
759                 tempChecksumFile.delete();
760             }
761         }
762         return correctChecksum || allNotFound;
763     }
764
765     /**
766      * Used to move the temporary file to its real destination.  This is patterned from the way WagonManager handles
767      * its downloaded files.
768      *
769      * @param temp   The completed download file
770      * @param target The final location of the downloaded file
771      * @throws ProxyException when the temp file cannot replace the target file
772      */
773     private void moveTempToTarget( File temp, File target )
774         throws ProxyException
775     {
776         if ( target.exists() && !target.delete() )
777         {
778             throw new ProxyException( "Unable to overwrite existing target file: " + target.getAbsolutePath() );
779         }
780
781         if ( !temp.renameTo( target ) )
782         {
783             getLogger().warn( "Unable to rename tmp file to its final name... resorting to copy command." );
784
785             try
786             {
787                 FileUtils.copyFile( temp, target );
788             }
789             catch ( IOException e )
790             {
791                 throw new ProxyException( "Cannot copy tmp file to its final location", e );
792             }
793             finally
794             {
795                 temp.delete();
796             }
797         }
798     }
799
800     /**
801      * Used to disconnect the wagonManager from its repository
802      *
803      * @param wagon the connected wagonManager object
804      */
805     private void disconnectWagon( Wagon wagon )
806     {
807         try
808         {
809             wagon.disconnect();
810         }
811         catch ( ConnectionException e )
812         {
813             getLogger().error( "Problem disconnecting from wagonManager - ignoring: " + e.getMessage() );
814         }
815     }
816
817     private void processRepositoryFailure( ProxiedArtifactRepository repository, Throwable t, String path,
818                                            ArtifactRepositoryPolicy policy )
819         throws ProxyException
820     {
821         repository.addFailure( path, policy );
822
823         String message = t.getMessage();
824         if ( repository.isHardFail() )
825         {
826             repository.addFailure( path, policy );
827             throw new ProxyException(
828                 "An error occurred in hardfailing repository " + repository.getName() + "...\n    " + message, t );
829         }
830
831         getLogger().warn( "Skipping repository " + repository.getName() + ": " + message );
832         getLogger().debug( "Cause", t );
833     }
834
835     private void processRepositoryFailure( ProxiedArtifactRepository repository, String message, String path,
836                                            ArtifactRepositoryPolicy policy )
837         throws ProxyException
838     {
839         repository.addFailure( path, policy );
840
841         processCachedRepositoryFailure( repository, message );
842     }
843
844     private void processCachedRepositoryFailure( ProxiedArtifactRepository repository, String message )
845         throws ProxyException
846     {
847         if ( repository.isHardFail() )
848         {
849             throw new ProxyException(
850                 "An error occurred in hardfailing repository " + repository.getName() + "...\n    " + message );
851         }
852
853         getLogger().warn( "Skipping repository " + repository.getName() + ": " + message );
854     }
855 }