001 package org.apache.maven.repository.legacy;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.io.File;
023 import java.io.IOException;
024 import java.security.NoSuchAlgorithmException;
025 import java.util.ArrayList;
026 import java.util.HashMap;
027 import java.util.List;
028 import java.util.Map;
029
030 import org.apache.maven.artifact.Artifact;
031 import org.apache.maven.artifact.metadata.ArtifactMetadata;
032 import org.apache.maven.artifact.repository.ArtifactRepository;
033 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
034 import org.apache.maven.wagon.ConnectionException;
035 import org.apache.maven.wagon.ResourceDoesNotExistException;
036 import org.apache.maven.wagon.TransferFailedException;
037 import org.apache.maven.wagon.UnsupportedProtocolException;
038 import org.apache.maven.wagon.Wagon;
039 import org.apache.maven.wagon.authentication.AuthenticationException;
040 import org.apache.maven.wagon.authentication.AuthenticationInfo;
041 import org.apache.maven.wagon.authorization.AuthorizationException;
042 import org.apache.maven.wagon.events.TransferListener;
043 import org.apache.maven.wagon.observers.ChecksumObserver;
044 import org.apache.maven.wagon.proxy.ProxyInfo;
045 import org.apache.maven.wagon.repository.Repository;
046 import org.codehaus.plexus.PlexusContainer;
047 import org.codehaus.plexus.component.annotations.Component;
048 import org.codehaus.plexus.component.annotations.Requirement;
049 import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
050 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
051 import org.codehaus.plexus.logging.Logger;
052 import org.codehaus.plexus.util.FileUtils;
053
054 //TODO: remove the update check manager
055 //TODO: separate into retriever and publisher
056 //TODO: remove hardcoding of checksum logic
057 @Component( role = WagonManager.class )
058 public class DefaultWagonManager
059 implements WagonManager
060 {
061 private static final String[] CHECKSUM_IDS = { "md5", "sha1" };
062
063 /** have to match the CHECKSUM_IDS */
064 private static final String[] CHECKSUM_ALGORITHMS = { "MD5", "SHA-1" };
065
066 @Requirement
067 private Logger logger;
068
069 @Requirement
070 private PlexusContainer container;
071
072 @Requirement
073 private UpdateCheckManager updateCheckManager;
074
075 //
076 // Retriever
077 //
078 public void getArtifact( Artifact artifact, ArtifactRepository repository, TransferListener downloadMonitor,
079 boolean force )
080 throws TransferFailedException, ResourceDoesNotExistException
081 {
082 String remotePath = repository.pathOf( artifact );
083
084 ArtifactRepositoryPolicy policy = artifact.isSnapshot() ? repository.getSnapshots() : repository.getReleases();
085
086 if ( !policy.isEnabled() )
087 {
088 logger.debug( "Skipping disabled repository " + repository.getId() + " for resolution of "
089 + artifact.getId() );
090 }
091 else if ( artifact.isSnapshot() || !artifact.getFile().exists() )
092 {
093 if ( force || updateCheckManager.isUpdateRequired( artifact, repository ) )
094 {
095 logger.debug( "Trying repository " + repository.getId() + " for resolution of " + artifact.getId()
096 + " from " + remotePath );
097
098 try
099 {
100 getRemoteFile( repository, artifact.getFile(), remotePath, downloadMonitor,
101 policy.getChecksumPolicy(), false );
102
103 updateCheckManager.touch( artifact, repository, null );
104 }
105 catch ( ResourceDoesNotExistException e )
106 {
107 updateCheckManager.touch( artifact, repository, null );
108 throw e;
109 }
110 catch ( TransferFailedException e )
111 {
112 String error = ( e.getMessage() != null ) ? e.getMessage() : e.getClass().getSimpleName();
113 updateCheckManager.touch( artifact, repository, error );
114 throw e;
115 }
116
117 logger.debug( " Artifact " + artifact.getId() + " resolved to " + artifact.getFile() );
118
119 artifact.setResolved( true );
120 }
121 else if ( !artifact.getFile().exists() )
122 {
123 String error = updateCheckManager.getError( artifact, repository );
124 if ( error != null )
125 {
126 throw new TransferFailedException( "Failure to resolve " + remotePath + " from "
127 + repository.getUrl() + " was cached in the local repository. "
128 + "Resolution will not be reattempted until the update interval of " + repository.getId()
129 + " has elapsed or updates are forced. Original error: " + error );
130 }
131 else
132 {
133 throw new ResourceDoesNotExistException( "Failure to resolve " + remotePath + " from "
134 + repository.getUrl() + " was cached in the local repository. "
135 + "Resolution will not be reattempted until the update interval of " + repository.getId()
136 + " has elapsed or updates are forced." );
137 }
138 }
139 }
140 }
141
142 public void getArtifact( Artifact artifact, List<ArtifactRepository> remoteRepositories,
143 TransferListener downloadMonitor, boolean force )
144 throws TransferFailedException, ResourceDoesNotExistException
145 {
146 TransferFailedException tfe = null;
147
148 for ( ArtifactRepository repository : remoteRepositories )
149 {
150 try
151 {
152 getArtifact( artifact, repository, downloadMonitor, force );
153
154 if ( artifact.isResolved() )
155 {
156 artifact.setRepository( repository );
157 break;
158 }
159 }
160 catch ( ResourceDoesNotExistException e )
161 {
162 // This one we will eat when looking through remote repositories
163 // because we want to cycle through them all before squawking.
164
165 logger.debug( "Unable to find artifact " + artifact.getId() + " in repository " + repository.getId()
166 + " (" + repository.getUrl() + ")", e );
167 }
168 catch ( TransferFailedException e )
169 {
170 tfe = e;
171
172 String msg =
173 "Unable to get artifact " + artifact.getId() + " from repository " + repository.getId() + " ("
174 + repository.getUrl() + "): " + e.getMessage();
175 if ( logger.isDebugEnabled() )
176 {
177 logger.warn( msg, e );
178 }
179 else
180 {
181 logger.warn( msg );
182 }
183 }
184 }
185
186 // if it already exists locally we were just trying to force it - ignore the update
187 if ( !artifact.getFile().exists() )
188 {
189 if ( tfe != null )
190 {
191 throw tfe;
192 }
193 else
194 {
195 throw new ResourceDoesNotExistException( "Unable to download the artifact from any repository" );
196 }
197 }
198 }
199
200 public void getArtifactMetadata( ArtifactMetadata metadata, ArtifactRepository repository, File destination,
201 String checksumPolicy )
202 throws TransferFailedException, ResourceDoesNotExistException
203 {
204 String remotePath = repository.pathOfRemoteRepositoryMetadata( metadata );
205
206 getRemoteFile( repository, destination, remotePath, null, checksumPolicy, true );
207 }
208
209 public void getArtifactMetadataFromDeploymentRepository( ArtifactMetadata metadata, ArtifactRepository repository,
210 File destination, String checksumPolicy )
211 throws TransferFailedException, ResourceDoesNotExistException
212 {
213 String remotePath = repository.pathOfRemoteRepositoryMetadata( metadata );
214
215 getRemoteFile( repository, destination, remotePath, null, checksumPolicy, true );
216 }
217
218 /**
219 * Deal with connecting to a wagon repository taking into account authentication and proxies.
220 *
221 * @param wagon
222 * @param repository
223 * @throws ConnectionException
224 * @throws AuthenticationException
225 */
226 private void connectWagon( Wagon wagon, ArtifactRepository repository )
227 throws ConnectionException, AuthenticationException
228 {
229 if ( repository.getProxy() != null && logger.isDebugEnabled() )
230 {
231 logger.debug( "Using proxy " + repository.getProxy().getHost() + ":" + repository.getProxy().getPort()
232 + " for " + repository.getUrl() );
233 }
234
235 if ( repository.getAuthentication() != null && repository.getProxy() != null )
236 {
237 wagon.connect( new Repository( repository.getId(), repository.getUrl() ), authenticationInfo( repository ),
238 proxyInfo( repository ) );
239 }
240 else if ( repository.getAuthentication() != null )
241 {
242 wagon.connect( new Repository( repository.getId(), repository.getUrl() ),
243 authenticationInfo( repository ) );
244 }
245 else if ( repository.getProxy() != null )
246 {
247 wagon.connect( new Repository( repository.getId(), repository.getUrl() ), proxyInfo( repository ) );
248 }
249 else
250 {
251 wagon.connect( new Repository( repository.getId(), repository.getUrl() ) );
252 }
253 }
254
255 private AuthenticationInfo authenticationInfo( ArtifactRepository repository )
256 {
257 AuthenticationInfo ai = new AuthenticationInfo();
258 ai.setUserName( repository.getAuthentication().getUsername() );
259 ai.setPassword( repository.getAuthentication().getPassword() );
260 return ai;
261 }
262
263 private ProxyInfo proxyInfo( ArtifactRepository repository )
264 {
265 ProxyInfo proxyInfo = new ProxyInfo();
266 proxyInfo.setHost( repository.getProxy().getHost() );
267 proxyInfo.setType( repository.getProxy().getProtocol() );
268 proxyInfo.setPort( repository.getProxy().getPort() );
269 proxyInfo.setNonProxyHosts( repository.getProxy().getNonProxyHosts() );
270 proxyInfo.setUserName( repository.getProxy().getUserName() );
271 proxyInfo.setPassword( repository.getProxy().getPassword() );
272 return proxyInfo;
273 }
274
275 public void getRemoteFile( ArtifactRepository repository, File destination, String remotePath,
276 TransferListener downloadMonitor, String checksumPolicy, boolean force )
277 throws TransferFailedException, ResourceDoesNotExistException
278 {
279 String protocol = repository.getProtocol();
280
281 Wagon wagon;
282
283 try
284 {
285 wagon = getWagon( protocol );
286 }
287 catch ( UnsupportedProtocolException e )
288 {
289 throw new TransferFailedException( "Unsupported Protocol: '" + protocol + "': " + e.getMessage(), e );
290 }
291
292 if ( downloadMonitor != null )
293 {
294 wagon.addTransferListener( downloadMonitor );
295 }
296
297 File temp = new File( destination + ".tmp" );
298
299 temp.deleteOnExit();
300
301 boolean downloaded = false;
302
303 try
304 {
305 connectWagon( wagon, repository );
306
307 boolean firstRun = true;
308 boolean retry = true;
309
310 // this will run at most twice. The first time, the firstRun flag is turned off, and if the retry flag
311 // is set on the first run, it will be turned off and not re-set on the second try. This is because the
312 // only way the retry flag can be set is if ( firstRun == true ).
313 while ( firstRun || retry )
314 {
315 ChecksumObserver md5ChecksumObserver = null;
316 ChecksumObserver sha1ChecksumObserver = null;
317 try
318 {
319 // TODO: configure on repository
320 int i = 0;
321
322 md5ChecksumObserver = addChecksumObserver( wagon, CHECKSUM_ALGORITHMS[i++] );
323 sha1ChecksumObserver = addChecksumObserver( wagon, CHECKSUM_ALGORITHMS[i++] );
324
325 // reset the retry flag.
326 retry = false;
327
328 // This should take care of creating destination directory now on
329 if ( destination.exists() && !force )
330 {
331 try
332 {
333 downloaded = wagon.getIfNewer( remotePath, temp, destination.lastModified() );
334
335 if ( !downloaded )
336 {
337 // prevent additional checks of this artifact until it expires again
338 destination.setLastModified( System.currentTimeMillis() );
339 }
340 }
341 catch ( UnsupportedOperationException e )
342 {
343 // older wagons throw this. Just get() instead
344 wagon.get( remotePath, temp );
345
346 downloaded = true;
347 }
348 }
349 else
350 {
351 wagon.get( remotePath, temp );
352 downloaded = true;
353 }
354 }
355 finally
356 {
357 wagon.removeTransferListener( md5ChecksumObserver );
358 wagon.removeTransferListener( sha1ChecksumObserver );
359 }
360
361 if ( downloaded )
362 {
363 // keep the checksum files from showing up on the download monitor...
364 if ( downloadMonitor != null )
365 {
366 wagon.removeTransferListener( downloadMonitor );
367 }
368
369 // try to verify the SHA-1 checksum for this file.
370 try
371 {
372 verifyChecksum( sha1ChecksumObserver, destination, temp, remotePath, ".sha1", wagon );
373 }
374 catch ( ChecksumFailedException e )
375 {
376 // if we catch a ChecksumFailedException, it means the transfer/read succeeded, but the checksum
377 // doesn't match. This could be a problem with the server (ibiblio HTTP-200 error page), so we'll
378 // try this up to two times. On the second try, we'll handle it as a bona-fide error, based on the
379 // repository's checksum checking policy.
380 if ( firstRun )
381 {
382 logger.warn( "*** CHECKSUM FAILED - " + e.getMessage() + " - RETRYING" );
383 retry = true;
384 }
385 else
386 {
387 handleChecksumFailure( checksumPolicy, e.getMessage(), e.getCause() );
388 }
389 }
390 catch ( ResourceDoesNotExistException sha1TryException )
391 {
392 logger.debug( "SHA1 not found, trying MD5: " + sha1TryException.getMessage() );
393
394 // if this IS NOT a ChecksumFailedException, it was a problem with transfer/read of the checksum
395 // file...we'll try again with the MD5 checksum.
396 try
397 {
398 verifyChecksum( md5ChecksumObserver, destination, temp, remotePath, ".md5", wagon );
399 }
400 catch ( ChecksumFailedException e )
401 {
402 // if we also fail to verify based on the MD5 checksum, and the checksum transfer/read
403 // succeeded, then we need to determine whether to retry or handle it as a failure.
404 if ( firstRun )
405 {
406 retry = true;
407 }
408 else
409 {
410 handleChecksumFailure( checksumPolicy, e.getMessage(), e.getCause() );
411 }
412 }
413 catch ( ResourceDoesNotExistException md5TryException )
414 {
415 // this was a failed transfer, and we don't want to retry.
416 handleChecksumFailure( checksumPolicy, "Error retrieving checksum file for " + remotePath,
417 md5TryException );
418 }
419 }
420
421 // reinstate the download monitor...
422 if ( downloadMonitor != null )
423 {
424 wagon.addTransferListener( downloadMonitor );
425 }
426 }
427
428 // unset the firstRun flag, so we don't get caught in an infinite loop...
429 firstRun = false;
430 }
431 }
432 catch ( ConnectionException e )
433 {
434 throw new TransferFailedException( "Connection failed: " + e.getMessage(), e );
435 }
436 catch ( AuthenticationException e )
437 {
438 throw new TransferFailedException( "Authentication failed: " + e.getMessage(), e );
439 }
440 catch ( AuthorizationException e )
441 {
442 throw new TransferFailedException( "Authorization failed: " + e.getMessage(), e );
443 }
444 finally
445 {
446 // Remove remaining TransferListener instances (checksum handlers removed in above finally clause)
447 if ( downloadMonitor != null )
448 {
449 wagon.removeTransferListener( downloadMonitor );
450 }
451
452 disconnectWagon( wagon );
453
454 releaseWagon( protocol, wagon );
455 }
456
457 if ( downloaded )
458 {
459 if ( !temp.exists() )
460 {
461 throw new ResourceDoesNotExistException( "Downloaded file does not exist: " + temp );
462 }
463
464 // The temporary file is named destination + ".tmp" and is done this way to ensure
465 // that the temporary file is in the same file system as the destination because the
466 // File.renameTo operation doesn't really work across file systems.
467 // So we will attempt to do a File.renameTo for efficiency and atomicity, if this fails
468 // then we will use a brute force copy and delete the temporary file.
469
470 if ( !temp.renameTo( destination ) )
471 {
472 try
473 {
474 FileUtils.copyFile( temp, destination );
475
476 temp.delete();
477 }
478 catch ( IOException e )
479 {
480 throw new TransferFailedException( "Error copying temporary file to the final destination: "
481 + e.getMessage(), e );
482 }
483 }
484 }
485 }
486
487 //
488 // Publisher
489 //
490 public void putArtifact( File source, Artifact artifact, ArtifactRepository deploymentRepository,
491 TransferListener downloadMonitor )
492 throws TransferFailedException
493 {
494 putRemoteFile( deploymentRepository, source, deploymentRepository.pathOf( artifact ), downloadMonitor );
495 }
496
497 public void putArtifactMetadata( File source, ArtifactMetadata artifactMetadata, ArtifactRepository repository )
498 throws TransferFailedException
499 {
500 logger.info( "Uploading " + artifactMetadata );
501 putRemoteFile( repository, source, repository.pathOfRemoteRepositoryMetadata( artifactMetadata ), null );
502 }
503
504 public void putRemoteFile( ArtifactRepository repository, File source, String remotePath,
505 TransferListener downloadMonitor )
506 throws TransferFailedException
507 {
508 String protocol = repository.getProtocol();
509
510 Wagon wagon;
511 try
512 {
513 wagon = getWagon( protocol );
514 }
515 catch ( UnsupportedProtocolException e )
516 {
517 throw new TransferFailedException( "Unsupported Protocol: '" + protocol + "': " + e.getMessage(), e );
518 }
519
520 if ( downloadMonitor != null )
521 {
522 wagon.addTransferListener( downloadMonitor );
523 }
524
525 Map<String, ChecksumObserver> checksums = new HashMap<String, ChecksumObserver>( 2 );
526
527 Map<String, String> sums = new HashMap<String, String>( 2 );
528
529 // TODO: configure these on the repository
530 for ( int i = 0; i < CHECKSUM_IDS.length; i++ )
531 {
532 checksums.put( CHECKSUM_IDS[i], addChecksumObserver( wagon, CHECKSUM_ALGORITHMS[i] ) );
533 }
534
535 List<File> temporaryFiles = new ArrayList<File>();
536
537 try
538 {
539 try
540 {
541 connectWagon( wagon, repository );
542
543 wagon.put( source, remotePath );
544 }
545 finally
546 {
547 if ( downloadMonitor != null )
548 {
549 wagon.removeTransferListener( downloadMonitor );
550 }
551 }
552
553 // Pre-store the checksums as any future puts will overwrite them
554 for ( String extension : checksums.keySet() )
555 {
556 ChecksumObserver observer = checksums.get( extension );
557 sums.put( extension, observer.getActualChecksum() );
558 }
559
560 // We do this in here so we can checksum the artifact metadata too, otherwise it could be metadata itself
561 for ( String extension : checksums.keySet() )
562 {
563 // TODO: shouldn't need a file intermediatary - improve wagon to take a stream
564 File temp = File.createTempFile( "maven-artifact", null );
565 temp.deleteOnExit();
566 FileUtils.fileWrite( temp.getAbsolutePath(), "UTF-8", sums.get( extension ) );
567
568 temporaryFiles.add( temp );
569 wagon.put( temp, remotePath + "." + extension );
570 }
571 }
572 catch ( ConnectionException e )
573 {
574 throw new TransferFailedException( "Connection failed: " + e.getMessage(), e );
575 }
576 catch ( AuthenticationException e )
577 {
578 throw new TransferFailedException( "Authentication failed: " + e.getMessage(), e );
579 }
580 catch ( AuthorizationException e )
581 {
582 throw new TransferFailedException( "Authorization failed: " + e.getMessage(), e );
583 }
584 catch ( ResourceDoesNotExistException e )
585 {
586 throw new TransferFailedException( "Resource to deploy not found: " + e.getMessage(), e );
587 }
588 catch ( IOException e )
589 {
590 throw new TransferFailedException( "Error creating temporary file for deployment: " + e.getMessage(), e );
591 }
592 finally
593 {
594 // MNG-4543
595 cleanupTemporaryFiles( temporaryFiles );
596
597 // Remove every checksum listener
598 for ( String aCHECKSUM_IDS : CHECKSUM_IDS )
599 {
600 TransferListener checksumListener = checksums.get( aCHECKSUM_IDS );
601 if ( checksumListener != null )
602 {
603 wagon.removeTransferListener( checksumListener );
604 }
605 }
606
607 disconnectWagon( wagon );
608
609 releaseWagon( protocol, wagon );
610 }
611 }
612
613 private void cleanupTemporaryFiles( List<File> files )
614 {
615 for ( File file : files )
616 {
617 // really don't care if it failed here only log warning
618 try
619 {
620 file.delete();
621 }
622 catch ( Exception e )
623 {
624 logger.warn( "skip failed to delete temporary file : " + file.getAbsolutePath() + " , message "
625 + e.getMessage() );
626 }
627 }
628
629 }
630
631 private ChecksumObserver addChecksumObserver( Wagon wagon, String algorithm )
632 throws TransferFailedException
633 {
634 try
635 {
636 ChecksumObserver checksumObserver = new ChecksumObserver( algorithm );
637 wagon.addTransferListener( checksumObserver );
638 return checksumObserver;
639 }
640 catch ( NoSuchAlgorithmException e )
641 {
642 throw new TransferFailedException( "Unable to add checksum for unsupported algorithm " + algorithm, e );
643 }
644 }
645
646 private void handleChecksumFailure( String checksumPolicy, String message, Throwable cause )
647 throws ChecksumFailedException
648 {
649 if ( ArtifactRepositoryPolicy.CHECKSUM_POLICY_FAIL.equals( checksumPolicy ) )
650 {
651 throw new ChecksumFailedException( message, cause );
652 }
653 else if ( !ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE.equals( checksumPolicy ) )
654 {
655 // warn if it is set to anything other than ignore
656 logger.warn( "*** CHECKSUM FAILED - " + message + " - IGNORING" );
657 }
658 // otherwise it is ignore
659 }
660
661 private void verifyChecksum( ChecksumObserver checksumObserver, File destination, File tempDestination,
662 String remotePath, String checksumFileExtension, Wagon wagon )
663 throws ResourceDoesNotExistException, TransferFailedException, AuthorizationException
664 {
665 try
666 {
667 // grab it first, because it's about to change...
668 String actualChecksum = checksumObserver.getActualChecksum();
669
670 File tempChecksumFile = new File( tempDestination + checksumFileExtension + ".tmp" );
671 tempChecksumFile.deleteOnExit();
672 wagon.get( remotePath + checksumFileExtension, tempChecksumFile );
673
674 String expectedChecksum = FileUtils.fileRead( tempChecksumFile, "UTF-8" );
675
676 // remove whitespaces at the end
677 expectedChecksum = expectedChecksum.trim();
678
679 // check for 'ALGO (name) = CHECKSUM' like used by openssl
680 if ( expectedChecksum.regionMatches( true, 0, "MD", 0, 2 )
681 || expectedChecksum.regionMatches( true, 0, "SHA", 0, 3 ) )
682 {
683 int lastSpacePos = expectedChecksum.lastIndexOf( ' ' );
684 expectedChecksum = expectedChecksum.substring( lastSpacePos + 1 );
685 }
686 else
687 {
688 // remove everything after the first space (if available)
689 int spacePos = expectedChecksum.indexOf( ' ' );
690
691 if ( spacePos != -1 )
692 {
693 expectedChecksum = expectedChecksum.substring( 0, spacePos );
694 }
695 }
696 if ( expectedChecksum.equalsIgnoreCase( actualChecksum ) )
697 {
698 File checksumFile = new File( destination + checksumFileExtension );
699 if ( checksumFile.exists() )
700 {
701 checksumFile.delete();
702 }
703 FileUtils.copyFile( tempChecksumFile, checksumFile );
704 tempChecksumFile.delete();
705 }
706 else
707 {
708 throw new ChecksumFailedException( "Checksum failed on download: local = '" + actualChecksum
709 + "'; remote = '" + expectedChecksum + "'" );
710 }
711 }
712 catch ( IOException e )
713 {
714 throw new ChecksumFailedException( "Invalid checksum file", e );
715 }
716 }
717
718 private void disconnectWagon( Wagon wagon )
719 {
720 try
721 {
722 wagon.disconnect();
723 }
724 catch ( ConnectionException e )
725 {
726 logger.error( "Problem disconnecting from wagon - ignoring: " + e.getMessage() );
727 }
728 }
729
730 private void releaseWagon( String protocol, Wagon wagon )
731 {
732 try
733 {
734 container.release( wagon );
735 }
736 catch ( ComponentLifecycleException e )
737 {
738 logger.error( "Problem releasing wagon - ignoring: " + e.getMessage() );
739 logger.debug( "", e );
740 }
741 }
742
743 @Deprecated
744 public Wagon getWagon( Repository repository )
745 throws UnsupportedProtocolException
746 {
747 return getWagon( repository.getProtocol() );
748 }
749
750 @Deprecated
751 public Wagon getWagon( String protocol )
752 throws UnsupportedProtocolException
753 {
754 if ( protocol == null )
755 {
756 throw new UnsupportedProtocolException( "Unspecified protocol" );
757 }
758
759 String hint = protocol.toLowerCase( java.util.Locale.ENGLISH );
760
761 Wagon wagon;
762 try
763 {
764 wagon = container.lookup( Wagon.class, hint );
765 }
766 catch ( ComponentLookupException e )
767 {
768 throw new UnsupportedProtocolException( "Cannot find wagon which supports the requested protocol: "
769 + protocol, e );
770 }
771
772 return wagon;
773 }
774
775 }