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
80 * your average brown onion
81 * @plexus.component role-hint="default"
83 public class DefaultRepositoryProxyConnectors
84 implements RepositoryProxyConnectors, RegistryListener, Initializable
86 private Logger log = LoggerFactory.getLogger( DefaultRepositoryProxyConnectors.class );
91 private ArchivaConfiguration archivaConfiguration;
96 private RepositoryContentFactory repositoryFactory;
101 private MetadataTools metadataTools;
104 * @plexus.requirement role="org.apache.maven.archiva.policies.PreDownloadPolicy"
106 private Map<String, PreDownloadPolicy> preDownloadPolicies;
109 * @plexus.requirement role="org.apache.maven.archiva.policies.PostDownloadPolicy"
111 private Map<String, PostDownloadPolicy> postDownloadPolicies;
114 * @plexus.requirement role="org.apache.maven.archiva.policies.DownloadErrorPolicy"
116 private Map<String, DownloadErrorPolicy> downloadErrorPolicies;
119 * @plexus.requirement role-hint="default"
121 private UrlFailureCache urlFailureCache;
123 private Map<String, List<ProxyConnector>> proxyConnectorMap = new HashMap<String, List<ProxyConnector>>();
125 private Map<String, ProxyInfo> networkProxyMap = new HashMap<String, ProxyInfo>();
128 * @plexus.requirement
130 private RepositoryContentConsumers consumers;
133 * @plexus.requirement
135 private WagonFactory wagonFactory;
137 public File fetchFromProxies( ManagedRepositoryContent repository, ArtifactReference artifact )
138 throws ProxyDownloadException
140 File localFile = toLocalFile( repository, artifact );
142 Properties requestProperties = new Properties();
143 requestProperties.setProperty( "filetype", "artifact" );
144 requestProperties.setProperty( "version", artifact.getVersion() );
145 requestProperties.setProperty( "managedRepositoryId", repository.getId() );
147 List<ProxyConnector> connectors = getProxyConnectors( repository );
148 Map<String, Exception> previousExceptions = new LinkedHashMap<String, Exception>();
149 for ( ProxyConnector connector : connectors )
151 if ( connector.isDisabled() )
156 RemoteRepositoryContent targetRepository = connector.getTargetRepository();
157 requestProperties.setProperty( "remoteRepositoryId", targetRepository.getId() );
159 String targetPath = targetRepository.toPath( artifact );
163 File downloadedFile =
164 transferFile( connector, targetRepository, targetPath, repository, localFile, requestProperties,
167 if ( fileExists( downloadedFile ) )
169 log.debug( "Successfully transferred: " + downloadedFile.getAbsolutePath() );
170 return downloadedFile;
173 catch ( NotFoundException e )
175 log.debug( "Artifact " + Keys.toKey( artifact ) + " not found on repository \""
176 + targetRepository.getRepository().getId() + "\"." );
178 catch ( NotModifiedException e )
180 log.debug( "Artifact " + Keys.toKey( artifact ) + " not updated on repository \""
181 + targetRepository.getRepository().getId() + "\"." );
183 catch ( ProxyException e )
185 validatePolicies( this.downloadErrorPolicies, connector.getPolicies(), requestProperties, artifact,
186 targetRepository, localFile, e, previousExceptions );
190 if ( !previousExceptions.isEmpty() )
192 throw new ProxyDownloadException( "Failures occurred downloading from some remote repositories",
193 previousExceptions );
196 log.debug( "Exhausted all target repositories, artifact " + Keys.toKey( artifact ) + " not found." );
201 public File fetchFromProxies( ManagedRepositoryContent repository, String path )
203 File localFile = new File( repository.getRepoRoot(), path );
205 // no update policies for these paths
206 if ( localFile.exists() )
211 Properties requestProperties = new Properties();
212 requestProperties.setProperty( "filetype", "resource" );
213 requestProperties.setProperty( "managedRepositoryId", repository.getId() );
215 List<ProxyConnector> connectors = getProxyConnectors( repository );
216 for ( ProxyConnector connector : connectors )
218 if ( connector.isDisabled() )
223 RemoteRepositoryContent targetRepository = connector.getTargetRepository();
224 requestProperties.setProperty( "remoteRepositoryId", targetRepository.getId() );
226 String targetPath = path;
230 File downloadedFile =
231 transferFile( connector, targetRepository, targetPath, repository, localFile, requestProperties,
234 if ( fileExists( downloadedFile ) )
236 log.debug( "Successfully transferred: " + downloadedFile.getAbsolutePath() );
237 return downloadedFile;
240 catch ( NotFoundException e )
242 log.debug( "Resource " + path + " not found on repository \""
243 + targetRepository.getRepository().getId() + "\"." );
245 catch ( NotModifiedException e )
247 log.debug( "Resource " + path + " not updated on repository \""
248 + targetRepository.getRepository().getId() + "\"." );
250 catch ( ProxyException e )
252 log.warn( "Transfer error from repository \"" + targetRepository.getRepository().getId()
253 + "\" for resource " + path + ", continuing to next repository. Error message: " + e.getMessage() );
254 log.debug( "Full stack trace", e );
258 log.debug( "Exhausted all target repositories, resource " + path + " not found." );
263 public File fetchMetatadaFromProxies( ManagedRepositoryContent repository, String logicalPath )
265 File localFile = new File( repository.getRepoRoot(), logicalPath );
267 Properties requestProperties = new Properties();
268 requestProperties.setProperty( "filetype", "metadata" );
269 boolean metadataNeedsUpdating = false;
270 long originalTimestamp = getLastModified( localFile );
272 List<ProxyConnector> connectors = getProxyConnectors( repository );
273 for ( ProxyConnector connector : connectors )
275 if ( connector.isDisabled() )
280 RemoteRepositoryContent targetRepository = connector.getTargetRepository();
282 File localRepoFile = toLocalRepoFile( repository, targetRepository, logicalPath );
283 long originalMetadataTimestamp = getLastModified( localRepoFile );
287 transferFile( connector, targetRepository, logicalPath, repository, localRepoFile, requestProperties,
290 if ( hasBeenUpdated( localRepoFile, originalMetadataTimestamp ) )
292 metadataNeedsUpdating = true;
295 catch ( NotFoundException e )
297 log.debug( "Metadata " + logicalPath + " not found on remote repository \""
298 + targetRepository.getRepository().getId() + "\".", e );
300 catch ( NotModifiedException e )
302 log.debug( "Metadata " + logicalPath + " not updated on remote repository \""
303 + targetRepository.getRepository().getId() + "\".", e );
305 catch ( ProxyException e )
307 log.warn( "Transfer error from repository \"" + targetRepository.getRepository().getId()
308 + "\" for versioned Metadata " + logicalPath + ", continuing to next repository. Error message: "
310 log.debug( "Full stack trace", e );
314 if ( hasBeenUpdated( localFile, originalTimestamp ) )
316 metadataNeedsUpdating = true;
319 if ( metadataNeedsUpdating || !localFile.exists() )
323 metadataTools.updateMetadata( repository, logicalPath );
325 catch ( RepositoryMetadataException e )
327 log.warn( "Unable to update metadata " + localFile.getAbsolutePath() + ": " + e.getMessage(), e );
331 if ( fileExists( localFile ) )
339 private long getLastModified( File file )
341 if ( !file.exists() || !file.isFile() )
346 return file.lastModified();
349 private boolean hasBeenUpdated( File file, long originalLastModified )
351 if ( !file.exists() || !file.isFile() )
356 long currentLastModified = getLastModified( file );
357 return ( currentLastModified > originalLastModified );
360 private File toLocalRepoFile( ManagedRepositoryContent repository, RemoteRepositoryContent targetRepository,
363 String repoPath = metadataTools.getRepositorySpecificName( targetRepository, targetPath );
364 return new File( repository.getRepoRoot(), repoPath );
368 * Test if the provided ManagedRepositoryContent has any proxies configured for it.
370 public boolean hasProxies( ManagedRepositoryContent repository )
372 synchronized ( this.proxyConnectorMap )
374 return this.proxyConnectorMap.containsKey( repository.getId() );
378 private File toLocalFile( ManagedRepositoryContent repository, ArtifactReference artifact )
380 return repository.toFile( artifact );
384 * Simple method to test if the file exists on the local disk.
386 * @param file the file to test. (may be null)
387 * @return true if file exists. false if the file param is null, doesn't exist, or is not of type File.
389 private boolean fileExists( File file )
396 if ( !file.exists() )
401 if ( !file.isFile() )
410 * Perform the transfer of the file.
412 * @param connector the connector configuration to use.
413 * @param remoteRepository the remote repository get the resource from.
414 * @param remotePath the path in the remote repository to the resource to get.
415 * @param repository the managed repository that will hold the file
416 * @param resource the local file to place the downloaded resource into
417 * @param requestProperties the request properties to utilize for policy handling.
418 * @param executeConsumers whether to execute the consumers after proxying
419 * @return the local file that was downloaded, or null if not downloaded.
420 * @throws NotFoundException if the file was not found on the remote repository.
421 * @throws NotModifiedException if the localFile was present, and the resource was present on remote repository, but
422 * the remote resource is not newer than the local File.
423 * @throws ProxyException if transfer was unsuccessful.
425 private File transferFile( ProxyConnector connector, RemoteRepositoryContent remoteRepository, String remotePath,
426 ManagedRepositoryContent repository, File resource, Properties requestProperties,
427 boolean executeConsumers )
428 throws ProxyException, NotModifiedException
430 String url = remoteRepository.getURL().getUrl();
431 if ( !url.endsWith( "/" ) )
435 url = url + remotePath;
436 requestProperties.setProperty( "url", url );
438 // Is a whitelist defined?
439 if ( CollectionUtils.isNotEmpty( connector.getWhitelist() ) )
441 // Path must belong to whitelist.
442 if ( !matchesPattern( remotePath, connector.getWhitelist() ) )
444 log.debug( "Path [" + remotePath
445 + "] is not part of defined whitelist (skipping transfer from repository ["
446 + remoteRepository.getRepository().getName() + "])." );
451 // Is target path part of blacklist?
452 if ( matchesPattern( remotePath, connector.getBlacklist() ) )
454 log.debug( "Path [" + remotePath + "] is part of blacklist (skipping transfer from repository ["
455 + remoteRepository.getRepository().getName() + "])." );
459 // Handle pre-download policy
462 validatePolicies( this.preDownloadPolicies, connector.getPolicies(), requestProperties, resource );
464 catch ( PolicyViolationException e )
466 String emsg = "Transfer not attempted on " + url + " : " + e.getMessage();
467 if ( fileExists( resource ) )
469 log.info( emsg + ": using already present local file." );
479 File tmpResource = null;
481 File workingDirectory = createWorkingDirectory( repository );
487 RepositoryURL repoUrl = remoteRepository.getURL();
488 String protocol = repoUrl.getProtocol();
489 wagon = (Wagon) wagonFactory.getWagon( "wagon#" + protocol );
492 throw new ProxyException( "Unsupported target repository protocol: " + protocol );
495 boolean connected = connectToRepository( connector, wagon, remoteRepository );
498 tmpResource = new File( workingDirectory, resource.getName() );
499 transferSimpleFile( wagon, remoteRepository, remotePath, repository, resource, tmpResource );
501 // TODO: these should be used to validate the download based on the policies, not always downloaded
503 // save on connections since md5 is rarely used
505 transferChecksum( wagon, remoteRepository, remotePath, repository, resource, workingDirectory,
508 transferChecksum( wagon, remoteRepository, remotePath, repository, resource, workingDirectory,
512 catch ( NotFoundException e )
514 urlFailureCache.cacheFailure( url );
517 catch ( NotModifiedException e )
519 // Do not cache url here.
522 catch ( ProxyException e )
524 urlFailureCache.cacheFailure( url );
535 catch ( ConnectionException e )
537 log.warn( "Unable to disconnect wagon.", e );
542 // Handle post-download policies.
545 validatePolicies( this.postDownloadPolicies, connector.getPolicies(), requestProperties, tmpResource );
547 catch ( PolicyViolationException e )
549 log.info( "Transfer invalidated from " + url + " : " + e.getMessage() );
550 executeConsumers = false;
551 if ( !fileExists( tmpResource ) )
557 if ( resource != null )
559 synchronized ( resource.getAbsolutePath().intern() )
561 File directory = resource.getParentFile();
562 moveFileIfExists( tmpMd5, directory );
563 moveFileIfExists( tmpSha1, directory );
564 moveFileIfExists( tmpResource, directory );
570 FileUtils.deleteQuietly( workingDirectory );
573 if ( executeConsumers )
575 // Just-in-time update of the index and database by executing the consumers for this artifact
576 consumers.executeConsumers( connector.getSourceRepository().getRepository(), resource );
583 * Moves the file into repository location if it exists
585 * @param fileToMove this could be either the main artifact, sha1 or md5 checksum file.
586 * @param directory directory to write files to
588 private void moveFileIfExists( File fileToMove, File directory )
589 throws ProxyException
591 if ( fileToMove != null && fileToMove.exists() )
593 File newLocation = new File( directory, fileToMove.getName() );
594 moveTempToTarget( fileToMove, newLocation );
600 * Quietly transfer the checksum file from the remote repository to the local file.
603 * @param wagon the wagon instance (should already be connected) to use.
604 * @param remoteRepository the remote repository to transfer from.
605 * @param remotePath the remote path to the resource to get.
606 * @param repository the managed repository that will hold the file
607 * @param localFile the local file that should contain the downloaded contents
608 * @param type the type of checksum to transfer (example: ".md5" or ".sha1")
609 * @throws ProxyException if copying the downloaded file into place did not succeed.
611 private File transferChecksum( Wagon wagon, RemoteRepositoryContent remoteRepository, String remotePath,
612 ManagedRepositoryContent repository, File resource, File tmpDirectory, String ext )
613 throws ProxyException
615 String url = remoteRepository.getURL().getUrl() + remotePath + ext;
617 // Transfer checksum does not use the policy.
618 if ( urlFailureCache.hasFailedBefore( url ) )
623 File destFile = new File( tmpDirectory, resource.getName() + ext );
627 transferSimpleFile( wagon, remoteRepository, remotePath + ext, repository, resource, destFile );
628 log.debug( "Checksum " + url + " Downloaded: " + destFile + " to move to " + resource );
630 catch ( NotFoundException e )
632 urlFailureCache.cacheFailure( url );
633 log.debug( "Transfer failed, checksum not found: " + url );
634 // Consume it, do not pass this on.
636 catch ( NotModifiedException e )
638 log.debug( "Transfer skipped, checksum not modified: " + url );
639 // Consume it, do not pass this on.
641 catch ( ProxyException e )
643 urlFailureCache.cacheFailure( url );
644 log.warn( "Transfer failed on checksum: " + url + " : " + e.getMessage(), e );
645 // Critical issue, pass it on.
652 * Perform the transfer of the remote file to the local file specified.
654 * @param wagon the wagon instance to use.
655 * @param remoteRepository the remote repository to use
656 * @param remotePath the remote path to attempt to get
657 * @param repository the managed repository that will hold the file
658 * @param origFile the local file to save to
659 * @return The local file that was transfered.
660 * @throws ProxyException if there was a problem moving the downloaded file into place.
661 * @throws WagonException if there was a problem tranfering the file.
663 private void transferSimpleFile( Wagon wagon, RemoteRepositoryContent remoteRepository, String remotePath,
664 ManagedRepositoryContent repository, File origFile, File destFile )
665 throws ProxyException
667 assert ( remotePath != null );
669 // Transfer the file.
672 boolean success = false;
674 if ( !origFile.exists() )
676 log.debug( "Retrieving " + remotePath + " from " + remoteRepository.getRepository().getName() );
677 wagon.get( remotePath, destFile );
680 // You wouldn't get here on failure, a WagonException would have been thrown.
681 log.debug( "Downloaded successfully." );
685 log.debug( "Retrieving " + remotePath + " from " + remoteRepository.getRepository().getName()
687 success = wagon.getIfNewer( remotePath, destFile, origFile.lastModified() );
690 throw new NotModifiedException( "Not downloaded, as local file is newer than remote side: "
691 + origFile.getAbsolutePath() );
694 if ( destFile.exists() )
696 log.debug( "Downloaded successfully." );
700 catch ( ResourceDoesNotExistException e )
702 throw new NotFoundException( "Resource [" + remoteRepository.getURL() + "/" + remotePath
703 + "] does not exist: " + e.getMessage(), e );
705 catch ( WagonException e )
707 // TODO: shouldn't have to drill into the cause, but TransferFailedException is often not descriptive enough
710 "Download failure on resource [" + remoteRepository.getURL() + "/" + remotePath + "]:" + e.getMessage();
711 if ( e.getCause() != null )
713 msg += " (cause: " + e.getCause() + ")";
715 throw new ProxyException( msg, e );
720 * Apply the policies.
722 * @param policies the map of policies to execute. (Map of String policy keys, to {@link DownloadPolicy} objects)
723 * @param settings the map of settings for the policies to execute. (Map of String policy keys, to String policy
725 * @param request the request properties (utilized by the {@link DownloadPolicy#applyPolicy(String,Properties,File)}
727 * @param localFile the local file (utilized by the {@link DownloadPolicy#applyPolicy(String,Properties,File)})
729 private void validatePolicies( Map<String, ? extends DownloadPolicy> policies, Map<String, String> settings,
730 Properties request, File localFile )
731 throws PolicyViolationException
733 for ( Entry<String, ? extends DownloadPolicy> entry : policies.entrySet() )
735 String key = entry.getKey();
736 DownloadPolicy policy = entry.getValue();
737 String defaultSetting = policy.getDefaultOption();
738 String setting = StringUtils.defaultString( settings.get( key ), defaultSetting );
740 log.debug( "Applying [" + key + "] policy with [" + setting + "]" );
743 policy.applyPolicy( setting, request, localFile );
745 catch ( PolicyConfigurationException e )
747 log.error( e.getMessage(), e );
752 private void validatePolicies( Map<String, DownloadErrorPolicy> policies, Map<String, String> settings,
753 Properties request, ArtifactReference artifact, RemoteRepositoryContent content,
754 File localFile, ProxyException exception, Map<String, Exception> previousExceptions )
755 throws ProxyDownloadException
757 boolean process = true;
758 for ( Entry<String, ? extends DownloadErrorPolicy> entry : policies.entrySet() )
760 String key = entry.getKey();
761 DownloadErrorPolicy policy = entry.getValue();
762 String defaultSetting = policy.getDefaultOption();
763 String setting = StringUtils.defaultString( settings.get( key ), defaultSetting );
765 log.debug( "Applying [" + key + "] policy with [" + setting + "]" );
768 // all policies must approve the exception, any can cancel
769 process = policy.applyPolicy( setting, request, localFile, exception, previousExceptions );
775 catch ( PolicyConfigurationException e )
777 log.error( e.getMessage(), e );
783 // if the exception was queued, don't throw it
784 if ( !previousExceptions.containsKey( content.getId() ) )
786 throw new ProxyDownloadException(
787 "An error occurred in downloading from the remote repository, and the policy is to fail immediately",
788 content.getId(), exception );
793 // if the exception was queued, but cancelled, remove it
794 previousExceptions.remove( content.getId() );
797 log.warn( "Transfer error from repository \"" + content.getRepository().getId() + "\" for artifact "
798 + Keys.toKey( artifact ) + ", continuing to next repository. Error message: " + exception.getMessage() );
799 log.debug( "Full stack trace", exception );
803 * Creates a working directory in the repository root for this request
806 * @return file location of working directory
807 * @throws IOException
809 private File createWorkingDirectory( ManagedRepositoryContent repository )
811 // TODO: This is ugly - lets actually clean this up when we get the new repository api
814 File tmpDir = File.createTempFile( ".workingdirectory", null, new File( repository.getRepoRoot() ) );
819 catch ( IOException e )
821 throw new RuntimeException( "Could not create working directory for this request", e );
826 * Used to move the temporary file to its real destination. This is patterned from the way WagonManager handles its
829 * @param temp The completed download file
830 * @param target The final location of the downloaded file
831 * @throws ProxyException when the temp file cannot replace the target file
833 private void moveTempToTarget( File temp, File target )
834 throws ProxyException
836 if ( target.exists() && !target.delete() )
838 throw new ProxyException( "Unable to overwrite existing target file: " + target.getAbsolutePath() );
841 target.getParentFile().mkdirs();
842 if ( !temp.renameTo( target ) )
844 log.warn( "Unable to rename tmp file to its final name... resorting to copy command." );
848 FileUtils.copyFile( temp, target );
850 catch ( IOException e )
852 if ( target.exists() )
854 log.debug( "Tried to copy file " + temp.getName() + " to " + target.getAbsolutePath()
855 + " but file with this name already exists." );
859 throw new ProxyException( "Cannot copy tmp file " + temp.getAbsolutePath()
860 + " to its final location", e );
865 FileUtils.deleteQuietly( temp );
871 * Using wagon, connect to the remote repository.
873 * @param connector the connector configuration to utilize (for obtaining network proxy configuration from)
874 * @param wagon the wagon instance to establish the connection on.
875 * @param remoteRepository the remote repository to connect to.
876 * @return true if the connection was successful. false if not connected.
878 private boolean connectToRepository( ProxyConnector connector, Wagon wagon, RemoteRepositoryContent remoteRepository )
880 boolean connected = false;
882 final ProxyInfo networkProxy;
883 synchronized ( this.networkProxyMap )
885 networkProxy = (ProxyInfo) this.networkProxyMap.get( connector.getProxyId() );
888 if ( log.isDebugEnabled() )
890 if ( networkProxy != null )
892 // TODO: move to proxyInfo.toString()
894 "Using network proxy " + networkProxy.getHost() + ":" + networkProxy.getPort()
895 + " to connect to remote repository " + remoteRepository.getURL();
896 if ( networkProxy.getNonProxyHosts() != null )
898 msg += "; excluding hosts: " + networkProxy.getNonProxyHosts();
900 if ( StringUtils.isNotBlank( networkProxy.getUserName() ) )
902 msg += "; as user: " + networkProxy.getUserName();
908 AuthenticationInfo authInfo = null;
909 String username = remoteRepository.getRepository().getUsername();
910 String password = remoteRepository.getRepository().getPassword();
912 if ( StringUtils.isNotBlank( username ) && StringUtils.isNotBlank( password ) )
914 log.debug( "Using username " + username + " to connect to remote repository " + remoteRepository.getURL() );
915 authInfo = new AuthenticationInfo();
916 authInfo.setUserName( username );
917 authInfo.setPassword( password );
920 // Convert seconds to milliseconds
921 int timeoutInMilliseconds = remoteRepository.getRepository().getTimeout() * 1000;
924 wagon.setTimeout( timeoutInMilliseconds );
928 Repository wagonRepository =
929 new Repository( remoteRepository.getId(), remoteRepository.getURL().toString() );
930 wagon.connect( wagonRepository, authInfo, networkProxy );
933 catch ( ConnectionException e )
935 log.warn( "Could not connect to " + remoteRepository.getRepository().getName() + ": " + e.getMessage() );
938 catch ( AuthenticationException e )
940 log.warn( "Could not connect to " + remoteRepository.getRepository().getName() + ": " + e.getMessage() );
948 * Tests whitelist and blacklist patterns against path.
950 * @param path the path to test.
951 * @param patterns the list of patterns to check.
952 * @return true if the path matches at least 1 pattern in the provided patterns list.
954 private boolean matchesPattern( String path, List<String> patterns )
956 if ( CollectionUtils.isEmpty( patterns ) )
961 if ( !path.startsWith( "/" ) )
966 for ( String pattern : patterns )
968 if ( !pattern.startsWith( "/" ) )
970 pattern = "/" + pattern;
973 if ( SelectorUtils.matchPath( pattern, path, false ) )
983 * TODO: Ensure that list is correctly ordered based on configuration. See MRM-477
985 public List<ProxyConnector> getProxyConnectors( ManagedRepositoryContent repository )
987 synchronized ( this.proxyConnectorMap )
989 List<ProxyConnector> ret = (List<ProxyConnector>) this.proxyConnectorMap.get( repository.getId() );
992 return Collections.emptyList();
995 Collections.sort( ret, ProxyConnectorOrderComparator.getInstance() );
1000 public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue )
1002 if ( ConfigurationNames.isNetworkProxy( propertyName )
1003 || ConfigurationNames.isManagedRepositories( propertyName )
1004 || ConfigurationNames.isRemoteRepositories( propertyName )
1005 || ConfigurationNames.isProxyConnector( propertyName ) )
1007 initConnectorsAndNetworkProxies();
1011 public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue )
1016 @SuppressWarnings( "unchecked" )
1017 private void initConnectorsAndNetworkProxies()
1019 synchronized ( this.proxyConnectorMap )
1021 ProxyConnectorOrderComparator proxyOrderSorter = new ProxyConnectorOrderComparator();
1022 this.proxyConnectorMap.clear();
1024 List<ProxyConnectorConfiguration> proxyConfigs =
1025 archivaConfiguration.getConfiguration().getProxyConnectors();
1026 for ( ProxyConnectorConfiguration proxyConfig : proxyConfigs )
1028 String key = proxyConfig.getSourceRepoId();
1032 // Create connector object.
1033 ProxyConnector connector = new ProxyConnector();
1035 connector.setSourceRepository( repositoryFactory.getManagedRepositoryContent( proxyConfig.getSourceRepoId() ) );
1036 connector.setTargetRepository( repositoryFactory.getRemoteRepositoryContent( proxyConfig.getTargetRepoId() ) );
1038 connector.setProxyId( proxyConfig.getProxyId() );
1039 connector.setPolicies( proxyConfig.getPolicies() );
1040 connector.setOrder( proxyConfig.getOrder() );
1041 connector.setDisabled( proxyConfig.isDisabled() );
1043 // Copy any blacklist patterns.
1044 List<String> blacklist = new ArrayList<String>();
1045 if ( CollectionUtils.isNotEmpty( proxyConfig.getBlackListPatterns() ) )
1047 blacklist.addAll( proxyConfig.getBlackListPatterns() );
1049 connector.setBlacklist( blacklist );
1051 // Copy any whitelist patterns.
1052 List<String> whitelist = new ArrayList<String>();
1053 if ( CollectionUtils.isNotEmpty( proxyConfig.getWhiteListPatterns() ) )
1055 whitelist.addAll( proxyConfig.getWhiteListPatterns() );
1057 connector.setWhitelist( whitelist );
1059 // Get other connectors
1060 List<ProxyConnector> connectors = this.proxyConnectorMap.get( key );
1061 if ( connectors == null )
1063 // Create if we are the first.
1064 connectors = new ArrayList<ProxyConnector>();
1067 // Add the connector.
1068 connectors.add( connector );
1070 // Ensure the list is sorted.
1071 Collections.sort( connectors, proxyOrderSorter );
1073 // Set the key to the list of connectors.
1074 this.proxyConnectorMap.put( key, connectors );
1076 catch ( RepositoryNotFoundException e )
1078 log.warn( "Unable to use proxy connector: " + e.getMessage(), e );
1080 catch ( RepositoryException e )
1082 log.warn( "Unable to use proxy connector: " + e.getMessage(), e );
1088 synchronized ( this.networkProxyMap )
1090 this.networkProxyMap.clear();
1092 List<NetworkProxyConfiguration> networkProxies =
1093 archivaConfiguration.getConfiguration().getNetworkProxies();
1094 for ( NetworkProxyConfiguration networkProxyConfig : networkProxies )
1096 String key = networkProxyConfig.getId();
1098 ProxyInfo proxy = new ProxyInfo();
1100 proxy.setType( networkProxyConfig.getProtocol() );
1101 proxy.setHost( networkProxyConfig.getHost() );
1102 proxy.setPort( networkProxyConfig.getPort() );
1103 proxy.setUserName( networkProxyConfig.getUsername() );
1104 proxy.setPassword( networkProxyConfig.getPassword() );
1106 this.networkProxyMap.put( key, proxy );
1111 public void initialize()
1112 throws InitializationException
1114 initConnectorsAndNetworkProxies();
1115 archivaConfiguration.addChangeListener( this );