1 package org.apache.maven.archiva.proxy;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.LinkedHashMap;
28 import java.util.List;
30 import java.util.Properties;
31 import java.util.Map.Entry;
33 import org.apache.commons.collections.CollectionUtils;
34 import org.apache.commons.io.FileUtils;
35 import org.apache.commons.lang.StringUtils;
36 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
37 import org.apache.maven.archiva.configuration.ConfigurationNames;
38 import org.apache.maven.archiva.configuration.NetworkProxyConfiguration;
39 import org.apache.maven.archiva.configuration.ProxyConnectorConfiguration;
40 import org.apache.maven.archiva.model.ArtifactReference;
41 import org.apache.maven.archiva.model.Keys;
42 import org.apache.maven.archiva.model.RepositoryURL;
43 import org.apache.maven.archiva.policies.DownloadErrorPolicy;
44 import org.apache.maven.archiva.policies.DownloadPolicy;
45 import org.apache.maven.archiva.policies.PolicyConfigurationException;
46 import org.apache.maven.archiva.policies.PolicyViolationException;
47 import org.apache.maven.archiva.policies.PostDownloadPolicy;
48 import org.apache.maven.archiva.policies.PreDownloadPolicy;
49 import org.apache.maven.archiva.policies.ProxyDownloadException;
50 import org.apache.maven.archiva.policies.urlcache.UrlFailureCache;
51 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
52 import org.apache.maven.archiva.repository.RemoteRepositoryContent;
53 import org.apache.maven.archiva.repository.RepositoryContentFactory;
54 import org.apache.maven.archiva.repository.RepositoryException;
55 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
56 import org.apache.maven.archiva.repository.metadata.MetadataTools;
57 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
58 import org.apache.maven.archiva.repository.scanner.RepositoryContentConsumers;
59 import org.apache.maven.wagon.ConnectionException;
60 import org.apache.maven.wagon.ResourceDoesNotExistException;
61 import org.apache.maven.wagon.Wagon;
62 import org.apache.maven.wagon.WagonException;
63 import org.apache.maven.wagon.authentication.AuthenticationException;
64 import org.apache.maven.wagon.authentication.AuthenticationInfo;
65 import org.apache.maven.wagon.proxy.ProxyInfo;
66 import org.apache.maven.wagon.repository.Repository;
67 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
68 import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
69 import org.codehaus.plexus.registry.Registry;
70 import org.codehaus.plexus.registry.RegistryListener;
71 import org.codehaus.plexus.util.SelectorUtils;
72 import org.slf4j.Logger;
73 import org.slf4j.LoggerFactory;
76 * DefaultRepositoryProxyConnectors
79 * @todo exception handling needs work - "not modified" is not really an exceptional case, and it has more layers than your average brown onion
80 * @plexus.component role-hint="default"
82 public class DefaultRepositoryProxyConnectors
83 implements RepositoryProxyConnectors, RegistryListener, Initializable
85 private Logger log = LoggerFactory.getLogger( DefaultRepositoryProxyConnectors.class );
90 private ArchivaConfiguration archivaConfiguration;
95 private RepositoryContentFactory repositoryFactory;
100 private MetadataTools metadataTools;
103 * @plexus.requirement role="org.apache.maven.archiva.policies.PreDownloadPolicy"
105 private Map<String, PreDownloadPolicy> preDownloadPolicies;
108 * @plexus.requirement role="org.apache.maven.archiva.policies.PostDownloadPolicy"
110 private Map<String, PostDownloadPolicy> postDownloadPolicies;
113 * @plexus.requirement role="org.apache.maven.archiva.policies.DownloadErrorPolicy"
115 private Map<String, DownloadErrorPolicy> downloadErrorPolicies;
118 * @plexus.requirement role-hint="default"
120 private UrlFailureCache urlFailureCache;
122 private Map<String, List<ProxyConnector>> proxyConnectorMap = new HashMap<String, List<ProxyConnector>>();
124 private Map<String, ProxyInfo> networkProxyMap = new HashMap<String, ProxyInfo>();
127 * @plexus.requirement
129 private RepositoryContentConsumers consumers;
132 * @plexus.requirement
134 private WagonFactory wagonFactory;
136 public File fetchFromProxies( ManagedRepositoryContent repository, ArtifactReference artifact )
137 throws ProxyDownloadException
139 File workingDirectory = createWorkingDirectory(repository);
142 File localFile = toLocalFile( repository, artifact );
144 Properties requestProperties = new Properties();
145 requestProperties.setProperty( "filetype", "artifact" );
146 requestProperties.setProperty( "version", artifact.getVersion() );
147 requestProperties.setProperty( "managedRepositoryId", repository.getId() );
149 List<ProxyConnector> connectors = getProxyConnectors( repository );
150 Map<String, Exception> previousExceptions = new LinkedHashMap<String, Exception>();
151 for ( ProxyConnector connector : connectors )
153 if (connector.isDisabled())
158 RemoteRepositoryContent targetRepository = connector.getTargetRepository();
159 requestProperties.setProperty( "remoteRepositoryId", targetRepository.getId() );
161 String targetPath = targetRepository.toPath( artifact );
165 File downloadedFile =
166 transferFile( connector, targetRepository, targetPath, repository, workingDirectory, localFile, requestProperties,
169 if ( fileExists( downloadedFile ) )
171 log.debug( "Successfully transferred: " + downloadedFile.getAbsolutePath() );
172 return downloadedFile;
175 catch ( NotFoundException e )
177 log.debug( "Artifact " + Keys.toKey( artifact ) + " not found on repository \""
178 + targetRepository.getRepository().getId() + "\"." );
180 catch ( NotModifiedException e )
182 log.debug( "Artifact " + Keys.toKey( artifact ) + " not updated on repository \""
183 + targetRepository.getRepository().getId() + "\"." );
185 catch ( ProxyException e )
187 validatePolicies( this.downloadErrorPolicies, connector.getPolicies(), requestProperties, artifact,
188 targetRepository, localFile, e, previousExceptions );
192 if ( !previousExceptions.isEmpty() )
194 throw new ProxyDownloadException( "Failures occurred downloading from some remote repositories",
195 previousExceptions );
198 log.debug( "Exhausted all target repositories, artifact " + Keys.toKey( artifact ) + " not found." );
202 FileUtils.deleteQuietly(workingDirectory);
208 public File fetchFromProxies( ManagedRepositoryContent repository, String path )
210 File workingDir = createWorkingDirectory(repository);
213 File localFile = new File( repository.getRepoRoot(), path );
215 // no update policies for these paths
216 if ( localFile.exists() )
221 Properties requestProperties = new Properties();
222 requestProperties.setProperty( "filetype", "resource" );
223 requestProperties.setProperty( "managedRepositoryId", repository.getId() );
225 List<ProxyConnector> connectors = getProxyConnectors( repository );
226 for ( ProxyConnector connector : connectors )
228 if (connector.isDisabled())
233 RemoteRepositoryContent targetRepository = connector.getTargetRepository();
234 requestProperties.setProperty( "remoteRepositoryId", targetRepository.getId() );
236 String targetPath = path;
240 File downloadedFile =
241 transferFile( connector, targetRepository, targetPath, repository, workingDir, localFile, requestProperties, false );
243 if ( fileExists( downloadedFile ) )
245 log.debug( "Successfully transferred: " + downloadedFile.getAbsolutePath() );
246 return downloadedFile;
249 catch ( NotFoundException e )
251 log.debug( "Resource " + path + " not found on repository \""
252 + targetRepository.getRepository().getId() + "\"." );
254 catch ( NotModifiedException e )
256 log.debug( "Resource " + path + " not updated on repository \""
257 + targetRepository.getRepository().getId() + "\"." );
259 catch ( ProxyException e )
261 log.warn( "Transfer error from repository \"" + targetRepository.getRepository().getId()
262 + "\" for resource " + path + ", continuing to next repository. Error message: " + e.getMessage() );
263 log.debug( "Full stack trace", e );
267 log.debug( "Exhausted all target repositories, resource " + path + " not found." );
271 FileUtils.deleteQuietly(workingDir);
277 public File fetchMetatadaFromProxies(ManagedRepositoryContent repository, String logicalPath)
279 File workingDir = createWorkingDirectory(repository);
282 File localFile = new File(repository.getRepoRoot(), logicalPath);
284 Properties requestProperties = new Properties();
285 requestProperties.setProperty( "filetype", "metadata" );
286 boolean metadataNeedsUpdating = false;
287 long originalTimestamp = getLastModified( localFile );
289 List<ProxyConnector> connectors = getProxyConnectors( repository );
290 for ( ProxyConnector connector : connectors )
292 if (connector.isDisabled())
297 RemoteRepositoryContent targetRepository = connector.getTargetRepository();
299 File localRepoFile = toLocalRepoFile( repository, targetRepository, logicalPath );
300 long originalMetadataTimestamp = getLastModified( localRepoFile );
304 transferFile( connector, targetRepository, logicalPath, repository, workingDir, localRepoFile, requestProperties, true );
306 if ( hasBeenUpdated( localRepoFile, originalMetadataTimestamp ) )
308 metadataNeedsUpdating = true;
311 catch ( NotFoundException e )
313 log.debug( "Metadata " + logicalPath
314 + " not found on remote repository \""
315 + targetRepository.getRepository().getId() + "\".", e );
317 catch ( NotModifiedException e )
319 log.debug( "Metadata " + logicalPath
320 + " not updated on remote repository \""
321 + targetRepository.getRepository().getId() + "\".", e );
323 catch ( ProxyException e )
325 log.warn( "Transfer error from repository \"" + targetRepository.getRepository().getId() +
326 "\" for versioned Metadata " + logicalPath +
327 ", continuing to next repository. Error message: " + e.getMessage() );
328 log.debug( "Full stack trace", e );
332 if ( hasBeenUpdated( localFile, originalTimestamp ) )
334 metadataNeedsUpdating = true;
337 if ( metadataNeedsUpdating || !localFile.exists())
341 metadataTools.updateMetadata( repository, logicalPath );
343 catch ( RepositoryMetadataException e )
345 log.warn( "Unable to update metadata " + localFile.getAbsolutePath() + ": " + e.getMessage(), e );
349 if ( fileExists( localFile ) )
356 FileUtils.deleteQuietly(workingDir);
362 private long getLastModified( File file )
364 if ( !file.exists() || !file.isFile() )
369 return file.lastModified();
372 private boolean hasBeenUpdated( File file, long originalLastModified )
374 if ( !file.exists() || !file.isFile() )
379 long currentLastModified = getLastModified( file );
380 return ( currentLastModified > originalLastModified );
383 private File toLocalRepoFile( ManagedRepositoryContent repository, RemoteRepositoryContent targetRepository,
386 String repoPath = metadataTools.getRepositorySpecificName( targetRepository, targetPath );
387 return new File( repository.getRepoRoot(), repoPath );
391 * Test if the provided ManagedRepositoryContent has any proxies configured for it.
393 public boolean hasProxies( ManagedRepositoryContent repository )
395 synchronized ( this.proxyConnectorMap )
397 return this.proxyConnectorMap.containsKey( repository.getId() );
401 private File toLocalFile( ManagedRepositoryContent repository, ArtifactReference artifact )
403 return repository.toFile( artifact );
407 * Simple method to test if the file exists on the local disk.
409 * @param file the file to test. (may be null)
410 * @return true if file exists. false if the file param is null, doesn't exist, or is not of type File.
412 private boolean fileExists( File file )
419 if ( !file.exists() )
424 if ( !file.isFile() )
433 * Perform the transfer of the file.
435 * @param connector the connector configuration to use.
436 * @param remoteRepository the remote repository get the resource from.
437 * @param remotePath the path in the remote repository to the resource to get.
438 * @param repository the managed repository that will hold the file
439 * @param resource the local file to place the downloaded resource into
440 * @param requestProperties the request properties to utilize for policy handling.
441 * @param executeConsumers whether to execute the consumers after proxying
442 * @return the local file that was downloaded, or null if not downloaded.
443 * @throws NotFoundException if the file was not found on the remote repository.
444 * @throws NotModifiedException if the localFile was present, and the resource was present on remote repository,
445 * but the remote resource is not newer than the local File.
446 * @throws ProxyException if transfer was unsuccessful.
448 private File transferFile( ProxyConnector connector, RemoteRepositoryContent remoteRepository, String remotePath,
449 ManagedRepositoryContent repository, File workingDirectory, File resource, Properties requestProperties,
450 boolean executeConsumers )
451 throws ProxyException, NotModifiedException
453 String url = remoteRepository.getURL().getUrl();
454 if ( !url.endsWith( "/" ) )
458 url = url + remotePath;
459 requestProperties.setProperty( "url", url );
461 // Is a whitelist defined?
462 if ( CollectionUtils.isNotEmpty( connector.getWhitelist() ) )
464 // Path must belong to whitelist.
465 if ( !matchesPattern( remotePath, connector.getWhitelist() ) )
467 log.debug( "Path [" + remotePath +
468 "] is not part of defined whitelist (skipping transfer from repository [" +
469 remoteRepository.getRepository().getName() + "])." );
474 // Is target path part of blacklist?
475 if ( matchesPattern( remotePath, connector.getBlacklist() ) )
477 log.debug( "Path [" + remotePath + "] is part of blacklist (skipping transfer from repository [" +
478 remoteRepository.getRepository().getName() + "])." );
482 // Handle pre-download policy
485 validatePolicies( this.preDownloadPolicies, connector.getPolicies(), requestProperties, resource );
487 catch ( PolicyViolationException e )
489 String emsg = "Transfer not attempted on " + url + " : " + e.getMessage();
490 if ( fileExists( resource ) )
492 log.info( emsg + ": using already present local file." );
502 File tmpResource = null;
507 RepositoryURL repoUrl = remoteRepository.getURL();
508 String protocol = repoUrl.getProtocol();
509 wagon = (Wagon) wagonFactory.getWagon( "wagon#" + protocol );
512 throw new ProxyException( "Unsupported target repository protocol: " + protocol );
515 boolean connected = connectToRepository( connector, wagon, remoteRepository );
518 tmpResource = transferSimpleFile( wagon, remoteRepository, remotePath, repository, workingDirectory, resource );
520 // TODO: these should be used to validate the download based on the policies, not always downloaded to
521 // save on connections since md5 is rarely used
522 tmpSha1 = transferChecksum( wagon, remoteRepository, remotePath, repository, workingDirectory, resource, ".sha1" );
523 tmpMd5 = transferChecksum( wagon, remoteRepository, remotePath, repository, workingDirectory, resource, ".md5" );
526 catch ( NotFoundException e )
528 urlFailureCache.cacheFailure( url );
531 catch ( NotModifiedException e )
533 // Do not cache url here.
536 catch ( ProxyException e )
538 urlFailureCache.cacheFailure( url );
549 catch ( ConnectionException e )
551 log.warn( "Unable to disconnect wagon.", e );
556 // Handle post-download policies.
559 validatePolicies( this.postDownloadPolicies, connector.getPolicies(), requestProperties, tmpResource );
561 catch ( PolicyViolationException e )
563 log.info( "Transfer invalidated from " + url + " : " + e.getMessage() );
564 executeConsumers = false;
565 if ( !fileExists( tmpResource ) )
571 if (resource != null)
573 synchronized (resource.getAbsolutePath().intern())
575 File directory = resource.getParentFile();
576 moveFileIfExists(tmpMd5, directory);
577 moveFileIfExists(tmpSha1, directory);
578 moveFileIfExists(tmpResource, directory);
582 if ( executeConsumers )
584 // Just-in-time update of the index and database by executing the consumers for this artifact
585 consumers.executeConsumers( connector.getSourceRepository().getRepository(), resource );
594 * Moves the file into repository location if it exists
596 * @param fileToMove this could be either the main artifact, sha1 or md5 checksum file.
597 * @param directory directory to write files to
599 private void moveFileIfExists(File fileToMove, File directory) throws ProxyException
601 if (fileToMove != null && fileToMove.exists())
603 File newLocation = new File(directory, fileToMove.getName());
604 moveTempToTarget(fileToMove, newLocation);
610 * Quietly transfer the checksum file from the remote repository to the local file.
613 * @param wagon the wagon instance (should already be connected) to use.
614 * @param remoteRepository the remote repository to transfer from.
615 * @param remotePath the remote path to the resource to get.
616 * @param repository the managed repository that will hold the file
617 * @param localFile the local file that should contain the downloaded contents
618 * @param type the type of checksum to transfer (example: ".md5" or ".sha1")
619 * @throws ProxyException if copying the downloaded file into place did not succeed.
621 private File transferChecksum( Wagon wagon, RemoteRepositoryContent remoteRepository, String remotePath,
622 ManagedRepositoryContent repository, File workingDirectory, File localFile, String type )
623 throws ProxyException
625 File hashFile = new File( localFile.getAbsolutePath() + type );
626 File tmpChecksum = new File(workingDirectory, hashFile.getName());
627 String url = remoteRepository.getURL().getUrl() + remotePath;
629 // Transfer checksum does not use the policy.
630 if ( urlFailureCache.hasFailedBefore( url + type ) )
637 transferSimpleFile( wagon, remoteRepository, remotePath + type, repository, workingDirectory, hashFile );
638 log.debug( "Checksum" + type + " Downloaded: " + hashFile );
640 catch ( NotFoundException e )
642 urlFailureCache.cacheFailure( url + type );
643 log.debug( "Transfer failed, checksum not found: " + url );
644 // Consume it, do not pass this on.
646 catch ( NotModifiedException e )
648 log.debug( "Transfer skipped, checksum not modified: " + url );
649 // Consume it, do not pass this on.
651 catch ( ProxyException e )
653 urlFailureCache.cacheFailure( url + type );
654 log.warn( "Transfer failed on checksum: " + url + " : " + e.getMessage(), e );
655 // Critical issue, pass it on.
662 * Perform the transfer of the remote file to the local file specified.
664 * @param wagon the wagon instance to use.
665 * @param remoteRepository the remote repository to use
666 * @param remotePath the remote path to attempt to get
667 * @param repository the managed repository that will hold the file
668 * @param localFile the local file to save to
669 * @return The local file that was transfered.
670 * @throws ProxyException if there was a problem moving the downloaded file into place.
671 * @throws WagonException if there was a problem tranfering the file.
673 private File transferSimpleFile( Wagon wagon, RemoteRepositoryContent remoteRepository, String remotePath,
674 ManagedRepositoryContent repository, File workingDirectory, File localFile )
675 throws ProxyException
677 assert ( remotePath != null );
679 // Transfer the file.
684 temp = new File(workingDirectory, localFile.getName());
686 boolean success = false;
688 if ( !localFile.exists() )
690 log.debug( "Retrieving " + remotePath + " from " + remoteRepository.getRepository().getName() );
691 wagon.get( remotePath, temp );
694 // You wouldn't get here on failure, a WagonException would have been thrown.
695 log.debug( "Downloaded successfully." );
699 log.debug( "Retrieving " + remotePath + " from " + remoteRepository.getRepository().getName()
701 success = wagon.getIfNewer( remotePath, temp, localFile.lastModified() );
704 throw new NotModifiedException(
705 "Not downloaded, as local file is newer than remote side: " + localFile.getAbsolutePath() );
710 log.debug( "Downloaded successfully." );
716 catch ( ResourceDoesNotExistException e )
718 throw new NotFoundException(
719 "Resource [" + remoteRepository.getURL() + "/" + remotePath + "] does not exist: " + e.getMessage(),
722 catch ( WagonException e )
724 // TODO: shouldn't have to drill into the cause, but TransferFailedException is often not descriptive enough
727 "Download failure on resource [" + remoteRepository.getURL() + "/" + remotePath + "]:" + e.getMessage();
728 if ( e.getCause() != null )
730 msg += " (cause: " + e.getCause() + ")";
732 throw new ProxyException( msg, e );
737 * Apply the policies.
739 * @param policies the map of policies to execute. (Map of String policy keys, to {@link DownloadPolicy} objects)
740 * @param settings the map of settings for the policies to execute. (Map of String policy keys, to String policy setting)
741 * @param request the request properties (utilized by the {@link DownloadPolicy#applyPolicy(String,Properties,File)})
742 * @param localFile the local file (utilized by the {@link DownloadPolicy#applyPolicy(String,Properties,File)})
744 private void validatePolicies( Map<String, ? extends DownloadPolicy> policies, Map<String, String> settings,
745 Properties request, File localFile )
746 throws PolicyViolationException
748 for ( Entry<String, ? extends DownloadPolicy> entry : policies.entrySet() )
750 String key = entry.getKey();
751 DownloadPolicy policy = entry.getValue();
752 String defaultSetting = policy.getDefaultOption();
753 String setting = StringUtils.defaultString( settings.get( key ), defaultSetting );
755 log.debug( "Applying [" + key + "] policy with [" + setting + "]" );
758 policy.applyPolicy( setting, request, localFile );
760 catch ( PolicyConfigurationException e )
762 log.error( e.getMessage(), e );
767 private void validatePolicies( Map<String, DownloadErrorPolicy> policies, Map<String, String> settings,
768 Properties request, ArtifactReference artifact, RemoteRepositoryContent content,
769 File localFile, ProxyException exception, Map<String, Exception> previousExceptions )
770 throws ProxyDownloadException
772 boolean process = true;
773 for ( Entry<String, ? extends DownloadErrorPolicy> entry : policies.entrySet() )
775 String key = entry.getKey();
776 DownloadErrorPolicy policy = entry.getValue();
777 String defaultSetting = policy.getDefaultOption();
778 String setting = StringUtils.defaultString( settings.get( key ), defaultSetting );
780 log.debug( "Applying [" + key + "] policy with [" + setting + "]" );
783 // all policies must approve the exception, any can cancel
784 process = policy.applyPolicy( setting, request, localFile, exception, previousExceptions );
790 catch ( PolicyConfigurationException e )
792 log.error( e.getMessage(), e );
798 // if the exception was queued, don't throw it
799 if ( !previousExceptions.containsKey( content.getId() ) )
801 throw new ProxyDownloadException(
802 "An error occurred in downloading from the remote repository, and the policy is to fail immediately",
803 content.getId(), exception );
808 // if the exception was queued, but cancelled, remove it
809 previousExceptions.remove( content.getId() );
812 log.warn( "Transfer error from repository \"" + content.getRepository().getId() + "\" for artifact " +
813 Keys.toKey( artifact ) + ", continuing to next repository. Error message: " + exception.getMessage() );
814 log.debug( "Full stack trace", exception );
818 * Creates a working directory in the repository root for this request
820 * @return file location of working directory
822 private File createWorkingDirectory(ManagedRepositoryContent repository)
824 //TODO: This is ugly - lets actually clean this up when we get the new repository api
827 File tmpDir = File.createTempFile(".workingdirectory", null, new File(repository.getRepoRoot()));
832 catch (IOException e)
834 throw new RuntimeException("Could not create working directory for this request", e);
839 * Used to move the temporary file to its real destination. This is patterned from the way WagonManager handles
840 * its downloaded files.
842 * @param temp The completed download file
843 * @param target The final location of the downloaded file
844 * @throws ProxyException when the temp file cannot replace the target file
846 private void moveTempToTarget( File temp, File target )
847 throws ProxyException
849 if ( target.exists() && !target.delete() )
851 throw new ProxyException( "Unable to overwrite existing target file: " + target.getAbsolutePath() );
854 target.getParentFile().mkdirs();
855 if ( !temp.renameTo( target ) )
857 log.warn( "Unable to rename tmp file to its final name... resorting to copy command." );
861 FileUtils.copyFile( temp, target );
863 catch ( IOException e )
867 log.debug("Tried to copy file " + temp.getName() + " to " + target.getAbsolutePath() + " but file with this name already exists.");
871 throw new ProxyException( "Cannot copy tmp file " + temp.getAbsolutePath() + " to its final location", e );
876 FileUtils.deleteQuietly(temp);
882 * Using wagon, connect to the remote repository.
884 * @param connector the connector configuration to utilize (for obtaining network proxy configuration from)
885 * @param wagon the wagon instance to establish the connection on.
886 * @param remoteRepository the remote repository to connect to.
887 * @return true if the connection was successful. false if not connected.
889 private boolean connectToRepository( ProxyConnector connector, Wagon wagon,
890 RemoteRepositoryContent remoteRepository )
892 boolean connected = false;
894 final ProxyInfo networkProxy;
895 synchronized ( this.networkProxyMap )
897 networkProxy = (ProxyInfo) this.networkProxyMap.get( connector.getProxyId() );
900 if ( log.isDebugEnabled() )
902 if ( networkProxy != null )
904 // TODO: move to proxyInfo.toString()
906 "Using network proxy " + networkProxy.getHost() + ":" + networkProxy.getPort()
907 + " to connect to remote repository " + remoteRepository.getURL();
908 if ( networkProxy.getNonProxyHosts() != null )
910 msg += "; excluding hosts: " + networkProxy.getNonProxyHosts();
912 if ( StringUtils.isNotBlank( networkProxy.getUserName() ) )
914 msg += "; as user: " + networkProxy.getUserName();
920 AuthenticationInfo authInfo = null;
921 String username = remoteRepository.getRepository().getUsername();
922 String password = remoteRepository.getRepository().getPassword();
924 if ( StringUtils.isNotBlank( username ) && StringUtils.isNotBlank( password ) )
926 log.debug( "Using username " + username + " to connect to remote repository "
927 + remoteRepository.getURL() );
928 authInfo = new AuthenticationInfo();
929 authInfo.setUserName( username );
930 authInfo.setPassword( password );
933 //Convert seconds to milliseconds
934 int timeoutInMilliseconds = remoteRepository.getRepository().getTimeout() * 1000;
937 wagon.setTimeout(timeoutInMilliseconds);
941 Repository wagonRepository = new Repository( remoteRepository.getId(), remoteRepository.getURL().toString() );
942 wagon.connect( wagonRepository, authInfo, networkProxy );
945 catch ( ConnectionException e )
948 "Could not connect to " + remoteRepository.getRepository().getName() + ": " + e.getMessage() );
951 catch ( AuthenticationException e )
954 "Could not connect to " + remoteRepository.getRepository().getName() + ": " + e.getMessage() );
962 * Tests whitelist and blacklist patterns against path.
964 * @param path the path to test.
965 * @param patterns the list of patterns to check.
966 * @return true if the path matches at least 1 pattern in the provided patterns list.
968 private boolean matchesPattern( String path, List<String> patterns )
970 if ( CollectionUtils.isEmpty( patterns ) )
975 for ( String pattern : patterns )
977 if ( SelectorUtils.matchPath( pattern, path, false ) )
987 * TODO: Ensure that list is correctly ordered based on configuration. See MRM-477
989 public List<ProxyConnector> getProxyConnectors( ManagedRepositoryContent repository )
991 synchronized ( this.proxyConnectorMap )
993 List<ProxyConnector> ret = (List<ProxyConnector>) this.proxyConnectorMap.get( repository.getId() );
996 return Collections.emptyList();
999 Collections.sort( ret, ProxyConnectorOrderComparator.getInstance() );
1004 public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue )
1006 if ( ConfigurationNames.isNetworkProxy( propertyName ) ||
1007 ConfigurationNames.isManagedRepositories( propertyName ) ||
1008 ConfigurationNames.isRemoteRepositories( propertyName ) ||
1009 ConfigurationNames.isProxyConnector( propertyName ) )
1011 initConnectorsAndNetworkProxies();
1015 public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue )
1020 @SuppressWarnings("unchecked")
1021 private void initConnectorsAndNetworkProxies()
1023 synchronized ( this.proxyConnectorMap )
1025 ProxyConnectorOrderComparator proxyOrderSorter = new ProxyConnectorOrderComparator();
1026 this.proxyConnectorMap.clear();
1028 List<ProxyConnectorConfiguration> proxyConfigs = archivaConfiguration.getConfiguration()
1029 .getProxyConnectors();
1030 for ( ProxyConnectorConfiguration proxyConfig : proxyConfigs )
1032 String key = proxyConfig.getSourceRepoId();
1036 // Create connector object.
1037 ProxyConnector connector = new ProxyConnector();
1039 connector.setSourceRepository( repositoryFactory.getManagedRepositoryContent( proxyConfig
1040 .getSourceRepoId() ) );
1041 connector.setTargetRepository( repositoryFactory.getRemoteRepositoryContent( proxyConfig
1042 .getTargetRepoId() ) );
1044 connector.setProxyId( proxyConfig.getProxyId() );
1045 connector.setPolicies( proxyConfig.getPolicies() );
1046 connector.setOrder( proxyConfig.getOrder() );
1047 connector.setDisabled( proxyConfig.isDisabled() );
1049 // Copy any blacklist patterns.
1050 List<String> blacklist = new ArrayList<String>();
1051 if ( CollectionUtils.isNotEmpty( proxyConfig.getBlackListPatterns() ) )
1053 blacklist.addAll( proxyConfig.getBlackListPatterns() );
1055 connector.setBlacklist( blacklist );
1057 // Copy any whitelist patterns.
1058 List<String> whitelist = new ArrayList<String>();
1059 if ( CollectionUtils.isNotEmpty( proxyConfig.getWhiteListPatterns() ) )
1061 whitelist.addAll( proxyConfig.getWhiteListPatterns() );
1063 connector.setWhitelist( whitelist );
1065 // Get other connectors
1066 List<ProxyConnector> connectors = this.proxyConnectorMap.get( key );
1067 if ( connectors == null )
1069 // Create if we are the first.
1070 connectors = new ArrayList<ProxyConnector>();
1073 // Add the connector.
1074 connectors.add( connector );
1076 // Ensure the list is sorted.
1077 Collections.sort( connectors, proxyOrderSorter );
1079 // Set the key to the list of connectors.
1080 this.proxyConnectorMap.put( key, connectors );
1082 catch ( RepositoryNotFoundException e )
1084 log.warn( "Unable to use proxy connector: " + e.getMessage(), e );
1086 catch ( RepositoryException e )
1088 log.warn( "Unable to use proxy connector: " + e.getMessage(), e );
1094 synchronized ( this.networkProxyMap )
1096 this.networkProxyMap.clear();
1098 List<NetworkProxyConfiguration> networkProxies = archivaConfiguration.getConfiguration().getNetworkProxies();
1099 for ( NetworkProxyConfiguration networkProxyConfig : networkProxies )
1101 String key = networkProxyConfig.getId();
1103 ProxyInfo proxy = new ProxyInfo();
1105 proxy.setType( networkProxyConfig.getProtocol() );
1106 proxy.setHost( networkProxyConfig.getHost() );
1107 proxy.setPort( networkProxyConfig.getPort() );
1108 proxy.setUserName( networkProxyConfig.getUsername() );
1109 proxy.setPassword( networkProxyConfig.getPassword() );
1111 this.networkProxyMap.put( key, proxy );
1116 public void initialize()
1117 throws InitializationException
1119 initConnectorsAndNetworkProxies();
1120 archivaConfiguration.addChangeListener( this );