diff --git a/tools/maven-bundle-plugin/pom.xml b/tools/maven-bundle-plugin/pom.xml
index a9eaa54f4a..f4e5b2dbdf 100644
--- a/tools/maven-bundle-plugin/pom.xml
+++ b/tools/maven-bundle-plugin/pom.xml
@@ -220,6 +220,35 @@
3.8.1
provided
+
+ org.apache.maven
+ maven-settings
+ 3.8.1
+ provided
+
+
+ org.apache.maven
+ maven-settings-builder
+ 3.8.1
+ provided
+
+
+ org.apache.maven.wagon
+ wagon-provider-api
+ 3.5.3
+ provided
+
+
+
+ org.apache.maven.wagon
+ wagon-file
+ 3.5.3
+
+
+ org.apache.maven.wagon
+ wagon-http
+ 3.5.3
+
org.apache.maven.reporting
maven-reporting-api
diff --git a/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/ObrDeploy.java b/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/ObrDeploy.java
index 90a79f892a..d1c4f2bc22 100644
--- a/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/ObrDeploy.java
+++ b/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/ObrDeploy.java
@@ -29,7 +29,6 @@
import java.util.regex.Pattern;
import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.manager.WagonManager;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
@@ -40,6 +39,8 @@
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.crypto.SettingsDecrypter;
+import org.codehaus.plexus.PlexusContainer;
/**
@@ -123,10 +124,16 @@ public final class ObrDeploy extends AbstractMojo
private Settings settings;
/**
- * The Wagon manager.
+ * The Plexus container, used to look up the Wagon for the repository protocol.
*/
@Component
- private WagonManager m_wagonManager;
+ private PlexusContainer m_container;
+
+ /**
+ * Decrypts the passwords of the server and proxy settings.
+ */
+ @Component
+ private SettingsDecrypter m_settingsDecrypter;
/**
* Attached source artifact
@@ -182,7 +189,7 @@ else if ( "javadoc".equals( artifact.getClassifier() ) )
Log log = getLog();
ObrUpdate update;
- RemoteFileManager remoteFile = new RemoteFileManager( m_wagonManager, settings, log );
+ RemoteFileManager remoteFile = new RemoteFileManager( m_container, m_settingsDecrypter, settings, log );
openRepositoryConnection( remoteFile );
// ======== LOCK REMOTE OBR ========
diff --git a/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/ObrDeployFile.java b/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/ObrDeployFile.java
index 2230d0efb5..6a7fce6fa2 100644
--- a/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/ObrDeployFile.java
+++ b/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/ObrDeployFile.java
@@ -24,7 +24,6 @@
import java.util.Arrays;
import java.util.List;
-import org.apache.maven.artifact.manager.WagonManager;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
@@ -34,6 +33,8 @@
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.crypto.SettingsDecrypter;
+import org.codehaus.plexus.PlexusContainer;
/**
@@ -99,10 +100,16 @@ public final class ObrDeployFile extends AbstractFileMojo
private Settings settings;
/**
- * The Wagon manager.
+ * The Plexus container, used to look up the Wagon for the repository protocol.
*/
@Component
- private WagonManager m_wagonManager;
+ private PlexusContainer m_container;
+
+ /**
+ * Decrypts the passwords of the server and proxy settings.
+ */
+ @Component
+ private SettingsDecrypter m_settingsDecrypter;
public void execute() throws MojoExecutionException
@@ -135,7 +142,7 @@ else if ( "NONE".equalsIgnoreCase( remoteOBR ) || "false".equalsIgnoreCase( remo
Log log = getLog();
ObrUpdate update;
- RemoteFileManager remoteFile = new RemoteFileManager( m_wagonManager, settings, log );
+ RemoteFileManager remoteFile = new RemoteFileManager( m_container, m_settingsDecrypter, settings, log );
remoteFile.connect( repositoryId, url );
// ======== LOCK REMOTE OBR ========
diff --git a/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/ObrRemoteClean.java b/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/ObrRemoteClean.java
index 64061f9ee2..c6fbe218a9 100644
--- a/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/ObrRemoteClean.java
+++ b/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/ObrRemoteClean.java
@@ -48,7 +48,6 @@
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
-import org.apache.maven.artifact.manager.WagonManager;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
@@ -59,6 +58,8 @@
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.crypto.SettingsDecrypter;
+import org.codehaus.plexus.PlexusContainer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@@ -136,10 +137,16 @@ public final class ObrRemoteClean extends AbstractMojo
private Settings settings;
/**
- * The Wagon manager.
+ * The Plexus container, used to look up the Wagon for the repository protocol.
*/
@Component
- private WagonManager m_wagonManager;
+ private PlexusContainer m_container;
+
+ /**
+ * Decrypts the passwords of the server and proxy settings.
+ */
+ @Component
+ private SettingsDecrypter m_settingsDecrypter;
public void execute() throws MojoExecutionException
@@ -170,7 +177,7 @@ else if ( "NONE".equalsIgnoreCase( remoteOBR ) || "false".equalsIgnoreCase( remo
Log log = getLog();
- RemoteFileManager remoteFile = new RemoteFileManager( m_wagonManager, settings, log );
+ RemoteFileManager remoteFile = new RemoteFileManager( m_container, m_settingsDecrypter, settings, log );
openRepositoryConnection( remoteFile );
if ( null == prefixUrl )
{
diff --git a/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/RemoteFileManager.java b/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/RemoteFileManager.java
index c6958b297d..9b6e277519 100644
--- a/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/RemoteFileManager.java
+++ b/tools/maven-bundle-plugin/src/main/java/org/apache/felix/obrplugin/RemoteFileManager.java
@@ -24,22 +24,29 @@
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
+import java.util.List;
+import java.util.Locale;
-import org.apache.maven.artifact.manager.WagonManager;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.settings.Proxy;
+import org.apache.maven.settings.Server;
import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
+import org.apache.maven.settings.crypto.SettingsDecrypter;
import org.apache.maven.wagon.ConnectionException;
import org.apache.maven.wagon.ResourceDoesNotExistException;
import org.apache.maven.wagon.TransferFailedException;
import org.apache.maven.wagon.UnsupportedProtocolException;
import org.apache.maven.wagon.Wagon;
-import org.apache.maven.wagon.WagonException;
import org.apache.maven.wagon.authentication.AuthenticationException;
+import org.apache.maven.wagon.authentication.AuthenticationInfo;
import org.apache.maven.wagon.authorization.AuthorizationException;
import org.apache.maven.wagon.proxy.ProxyInfo;
import org.apache.maven.wagon.repository.Repository;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
/**
@@ -54,9 +61,14 @@ public class RemoteFileManager
private Wagon m_wagon;
/**
- * the wagon manager.
+ * the container used to look up the wagon for a protocol.
*/
- private WagonManager m_wagonManager;
+ private PlexusContainer m_container;
+
+ /**
+ * decrypts the passwords found in the settings, may be null.
+ */
+ private SettingsDecrypter m_settingsDecrypter;
/**
* the project settings.
@@ -68,16 +80,18 @@ public class RemoteFileManager
*/
private Log m_log;
-
/**
* initialize main information.
- * @param wm WagonManager provides by maven
+ * @param container container provided by maven, used to look up the Wagon component of a protocol
+ * @param settingsDecrypter decrypts server and proxy passwords, may be null to use them as they are
* @param settings settings of the current project provides by maven
* @param log logger
*/
- public RemoteFileManager( WagonManager wm, Settings settings, Log log )
+ public RemoteFileManager( PlexusContainer container, SettingsDecrypter settingsDecrypter, Settings settings,
+ Log log )
{
- m_wagonManager = wm;
+ m_container = container;
+ m_settingsDecrypter = settingsDecrypter;
m_settings = settings;
m_log = log;
m_wagon = null;
@@ -100,6 +114,59 @@ public void disconnect()
{
m_log.error( "Error disconnecting Wagon", e );
}
+ finally
+ {
+ releaseWagon();
+ }
+ }
+
+
+ /**
+ * Wagons are looked up per use, so give the instance back to the container.
+ */
+ private void releaseWagon()
+ {
+ if ( m_wagon != null )
+ {
+ try
+ {
+ m_container.release( m_wagon );
+ }
+ catch ( ComponentLifecycleException e )
+ {
+ m_log.debug( "Unable to release Wagon", e );
+ }
+ finally
+ {
+ m_wagon = null;
+ }
+ }
+ }
+
+
+ /**
+ * Look up the Wagon implementing the given protocol. The wagon providers for file and http(s) are shipped with
+ * this plugin, other protocols come from the Wagon providers of the build extensions.
+ * @param protocol repository protocol, e.g. file or https
+ * @return a new wagon instance
+ * @throws UnsupportedProtocolException if no Wagon is available for the protocol
+ */
+ Wagon lookupWagon( String protocol ) throws UnsupportedProtocolException
+ {
+ if ( protocol == null )
+ {
+ throw new UnsupportedProtocolException( "Unspecified protocol" );
+ }
+
+ try
+ {
+ return m_container.lookup( Wagon.class, protocol.toLowerCase( Locale.ENGLISH ) );
+ }
+ catch ( ComponentLookupException e )
+ {
+ throw new UnsupportedProtocolException( "Cannot find wagon which supports the requested protocol: "
+ + protocol, e );
+ }
}
@@ -115,35 +182,34 @@ public void connect( String id, String url ) throws MojoExecutionException
try
{
- m_wagon = m_wagonManager.getWagon( repository );
+ m_wagon = lookupWagon( repository.getProtocol() );
}
catch ( UnsupportedProtocolException e )
{
throw new MojoExecutionException( "Unsupported protocol: '" + repository.getProtocol() + "'", e );
}
- catch ( WagonException e )
- {
- throw new MojoExecutionException( "Unable to configure Wagon: '" + repository.getProtocol() + "'", e );
- }
try
{
- ProxyInfo proxyInfo = getProxyInfo( m_settings );
+ AuthenticationInfo authenticationInfo = getAuthenticationInfo( m_settings, m_settingsDecrypter, id );
+ ProxyInfo proxyInfo = getProxyInfo( m_settings, m_settingsDecrypter );
if ( proxyInfo != null )
{
- m_wagon.connect( repository, m_wagonManager.getAuthenticationInfo( id ), proxyInfo );
+ m_wagon.connect( repository, authenticationInfo, proxyInfo );
}
else
{
- m_wagon.connect( repository, m_wagonManager.getAuthenticationInfo( id ) );
+ m_wagon.connect( repository, authenticationInfo );
}
}
catch ( ConnectionException e )
{
+ releaseWagon();
throw new MojoExecutionException( "Connection failed", e );
}
catch ( AuthenticationException e )
{
+ releaseWagon();
throw new MojoExecutionException( "Authentication failed", e );
}
}
@@ -232,15 +298,32 @@ public void put( File file, String url ) throws MojoExecutionException
/**
* Convenience method to map a Proxy object from the user system settings to a ProxyInfo object.
+ * The proxy password is used as it is found in the settings.
* @param settings project settings given by maven
* @return a proxyInfo object instancied or null if no active proxy is define in the settings.xml
*/
public static ProxyInfo getProxyInfo( Settings settings )
+ {
+ return getProxyInfo( settings, null );
+ }
+
+
+ /**
+ * Map the active proxy of the user settings to a ProxyInfo object.
+ * @param settings project settings given by maven
+ * @param decrypter used to decrypt the proxy password, may be null
+ * @return a proxyInfo object instancied or null if no active proxy is define in the settings.xml
+ */
+ static ProxyInfo getProxyInfo( Settings settings, SettingsDecrypter decrypter )
{
ProxyInfo proxyInfo = null;
if ( settings != null && settings.getActiveProxy() != null )
{
Proxy settingsProxy = settings.getActiveProxy();
+ if ( decrypter != null )
+ {
+ settingsProxy = decrypter.decrypt( new DefaultSettingsDecryptionRequest( settingsProxy ) ).getProxy();
+ }
proxyInfo = new ProxyInfo();
proxyInfo.setHost( settingsProxy.getHost() );
@@ -255,6 +338,45 @@ public static ProxyInfo getProxyInfo( Settings settings )
}
+ /**
+ * Find the credentials for a repository id in the user settings, like Maven does for its own repositories.
+ * @param settings project settings given by maven
+ * @param decrypter used to decrypt the server passwords, may be null
+ * @param id repository id, matched case insensitively against the server ids
+ * @return the credentials of the matching server, or an empty object if there is none
+ */
+ static AuthenticationInfo getAuthenticationInfo( Settings settings, SettingsDecrypter decrypter, String id )
+ {
+ if ( settings != null && id != null )
+ {
+ List servers = settings.getServers();
+ if ( servers != null )
+ {
+ for ( Server server : servers )
+ {
+ if ( id.equalsIgnoreCase( server.getId() ) )
+ {
+ if ( decrypter != null )
+ {
+ server = decrypter.decrypt( new DefaultSettingsDecryptionRequest( server ) ).getServer();
+ }
+
+ AuthenticationInfo authInfo = new AuthenticationInfo();
+ authInfo.setUserName( server.getUsername() );
+ authInfo.setPassword( server.getPassword() );
+ authInfo.setPrivateKey( server.getPrivateKey() );
+ authInfo.setPassphrase( server.getPassphrase() );
+ return authInfo;
+ }
+ }
+ }
+ }
+
+ // an empty one, as Wagon expects authentication info to be present
+ return new AuthenticationInfo();
+ }
+
+
public void lockFile( String fileName, boolean ignoreLock ) throws MojoExecutionException
{
if ( !ignoreLock )
diff --git a/tools/maven-bundle-plugin/src/test/java/org/apache/felix/obrplugin/RemoteFileManagerTest.java b/tools/maven-bundle-plugin/src/test/java/org/apache/felix/obrplugin/RemoteFileManagerTest.java
new file mode 100644
index 0000000000..dfabb7b20b
--- /dev/null
+++ b/tools/maven-bundle-plugin/src/test/java/org/apache/felix/obrplugin/RemoteFileManagerTest.java
@@ -0,0 +1,353 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.obrplugin;
+
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.SystemStreamLog;
+import org.apache.maven.settings.Proxy;
+import org.apache.maven.settings.Server;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.crypto.SettingsDecrypter;
+import org.apache.maven.settings.crypto.SettingsDecryptionRequest;
+import org.apache.maven.settings.building.SettingsProblem;
+import org.apache.maven.settings.crypto.SettingsDecryptionResult;
+import org.apache.maven.wagon.UnsupportedProtocolException;
+import org.apache.maven.wagon.Wagon;
+import org.apache.maven.wagon.authentication.AuthenticationInfo;
+import org.apache.maven.wagon.proxy.ProxyInfo;
+import org.apache.maven.wagon.providers.file.FileWagon;
+import org.codehaus.plexus.PlexusContainer;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+
+public class RemoteFileManagerTest
+{
+ @Rule
+ public TemporaryFolder tmp = new TemporaryFolder();
+
+ private final List lookedUp = new ArrayList();
+
+ private final AtomicInteger released = new AtomicInteger();
+
+ private PlexusContainer container;
+
+ /** Prefixes every password, so a test can tell that the decrypter was used. */
+ private final SettingsDecrypter decrypter = new SettingsDecrypter()
+ {
+ public SettingsDecryptionResult decrypt( SettingsDecryptionRequest request )
+ {
+ Server server = request.getServers().isEmpty() ? null : request.getServers().get( 0 );
+ Proxy proxy = request.getProxies().isEmpty() ? null : request.getProxies().get( 0 );
+ if ( server != null )
+ {
+ server = server.clone();
+ server.setPassword( "decrypted-" + server.getPassword() );
+ }
+ if ( proxy != null )
+ {
+ proxy = proxy.clone();
+ proxy.setPassword( "decrypted-" + proxy.getPassword() );
+ }
+ return new Result( server, proxy );
+ }
+ };
+
+
+ private static final class Result implements SettingsDecryptionResult
+ {
+ private final Server server;
+
+ private final Proxy proxy;
+
+ Result( Server server, Proxy proxy )
+ {
+ this.server = server;
+ this.proxy = proxy;
+ }
+
+ public Server getServer()
+ {
+ return server;
+ }
+
+ public List getServers()
+ {
+ return server == null ? new ArrayList() : Collections.singletonList( server );
+ }
+
+ public Proxy getProxy()
+ {
+ return proxy;
+ }
+
+ public List getProxies()
+ {
+ return proxy == null ? new ArrayList() : Collections.singletonList( proxy );
+ }
+
+ public List getProblems()
+ {
+ return new ArrayList();
+ }
+ }
+
+
+ /** A container that only knows the file wagon, as the plugin realm would for the file protocol. */
+ @Before
+ public void createContainer()
+ {
+ container = ( PlexusContainer ) java.lang.reflect.Proxy.newProxyInstance( getClass().getClassLoader(),
+ new Class>[] { PlexusContainer.class }, ( proxy, method, args ) -> {
+ if ( "lookup".equals( method.getName() ) && args.length == 2 && args[1] instanceof String )
+ {
+ lookedUp.add( ( String ) args[1] );
+ if ( "file".equals( args[1] ) )
+ {
+ return new FileWagon();
+ }
+ throw new org.codehaus.plexus.component.repository.exception.ComponentLookupException(
+ "no such wagon", ( ( Class> ) args[0] ).getName(), ( String ) args[1] );
+ }
+ if ( "release".equals( method.getName() ) )
+ {
+ released.incrementAndGet();
+ return null;
+ }
+ throw new UnsupportedOperationException( method.getName() );
+ } );
+ }
+
+
+ private RemoteFileManager manager( Settings settings )
+ {
+ return new RemoteFileManager( container, decrypter, settings, new SystemStreamLog() );
+ }
+
+
+ private static Server server( String id, String user, String password )
+ {
+ Server server = new Server();
+ server.setId( id );
+ server.setUsername( user );
+ server.setPassword( password );
+ return server;
+ }
+
+
+ @Test
+ public void authenticationComesFromTheServerWithTheSameId()
+ {
+ Settings settings = new Settings();
+ settings.addServer( server( "other", "nobody", "secret" ) );
+ Server server = server( "obr", "alice", "s3cr3t" );
+ server.setPrivateKey( "/home/alice/key" );
+ server.setPassphrase( "phrase" );
+ settings.addServer( server );
+
+ AuthenticationInfo info = RemoteFileManager.getAuthenticationInfo( settings, decrypter, "OBR" );
+
+ assertEquals( "alice", info.getUserName() );
+ assertEquals( "decrypted-s3cr3t", info.getPassword() );
+ assertEquals( "/home/alice/key", info.getPrivateKey() );
+ assertEquals( "phrase", info.getPassphrase() );
+ }
+
+
+ @Test
+ public void authenticationWithoutDecrypterUsesPasswordAsIs()
+ {
+ Settings settings = new Settings();
+ settings.addServer( server( "obr", "alice", "s3cr3t" ) );
+
+ assertEquals( "s3cr3t", RemoteFileManager.getAuthenticationInfo( settings, null, "obr" ).getPassword() );
+ }
+
+
+ @Test
+ public void authenticationIsEmptyWhenNoServerMatches()
+ {
+ Settings settings = new Settings();
+ settings.addServer( server( "other", "nobody", "secret" ) );
+
+ AuthenticationInfo info = RemoteFileManager.getAuthenticationInfo( settings, decrypter, "obr" );
+
+ assertNotNull( info );
+ assertNull( info.getUserName() );
+ assertNull( info.getPassword() );
+ assertNotNull( RemoteFileManager.getAuthenticationInfo( null, decrypter, "obr" ) );
+ assertNotNull( RemoteFileManager.getAuthenticationInfo( settings, decrypter, null ) );
+ }
+
+
+ private static Proxy proxy( String id, boolean active, String host )
+ {
+ Proxy proxy = new Proxy();
+ proxy.setId( id );
+ proxy.setActive( active );
+ proxy.setProtocol( "http" );
+ proxy.setHost( host );
+ proxy.setPort( 3128 );
+ proxy.setNonProxyHosts( "localhost|*.example.org" );
+ proxy.setUsername( "pu" );
+ proxy.setPassword( "pp" );
+ return proxy;
+ }
+
+
+ @Test
+ public void proxyIsTheFirstActiveProxyWithDecryptedPassword()
+ {
+ Settings settings = new Settings();
+ settings.addProxy( proxy( "off", false, "inactive.example.com" ) );
+ settings.addProxy( proxy( "on", true, "proxy.example.com" ) );
+
+ ProxyInfo info = RemoteFileManager.getProxyInfo( settings, decrypter );
+
+ assertEquals( "proxy.example.com", info.getHost() );
+ assertEquals( 3128, info.getPort() );
+ assertEquals( "http", info.getType() );
+ assertEquals( "localhost|*.example.org", info.getNonProxyHosts() );
+ assertEquals( "pu", info.getUserName() );
+ assertEquals( "decrypted-pp", info.getPassword() );
+
+ assertEquals( "pp", RemoteFileManager.getProxyInfo( settings ).getPassword() );
+ }
+
+
+ @Test
+ public void noProxyWhenNoneIsActive()
+ {
+ Settings settings = new Settings();
+ assertNull( RemoteFileManager.getProxyInfo( settings, decrypter ) );
+ settings.addProxy( proxy( "off", false, "inactive.example.com" ) );
+ assertNull( RemoteFileManager.getProxyInfo( settings, decrypter ) );
+ assertNull( RemoteFileManager.getProxyInfo( null, decrypter ) );
+ }
+
+
+ @Test
+ public void wagonIsLookedUpByLowerCaseProtocol() throws Exception
+ {
+ Wagon wagon = manager( new Settings() ).lookupWagon( "FILE" );
+
+ assertTrue( wagon instanceof FileWagon );
+ assertEquals( Collections.singletonList( "file" ), lookedUp );
+ }
+
+
+ @Test
+ public void unknownProtocolIsRejected()
+ {
+ try
+ {
+ manager( new Settings() ).lookupWagon( "gopher" );
+ fail( "expected UnsupportedProtocolException" );
+ }
+ catch ( UnsupportedProtocolException e )
+ {
+ assertTrue( e.getMessage(), e.getMessage().contains( "gopher" ) );
+ }
+
+ try
+ {
+ manager( new Settings() ).lookupWagon( null );
+ fail( "expected UnsupportedProtocolException" );
+ }
+ catch ( UnsupportedProtocolException e )
+ {
+ // expected
+ }
+ }
+
+
+ @Test
+ public void connectReportsUnsupportedProtocol()
+ {
+ try
+ {
+ manager( new Settings() ).connect( "obr", "gopher://example.com/obr" );
+ fail( "expected MojoExecutionException" );
+ }
+ catch ( MojoExecutionException e )
+ {
+ assertEquals( "Unsupported protocol: 'gopher'", e.getMessage() );
+ }
+ }
+
+
+ @Test
+ public void lockUploadDownloadAndUnlockOnFileRepository() throws Exception
+ {
+ File remote = tmp.newFolder( "obr" );
+ RemoteFileManager manager = manager( new Settings() );
+ manager.connect( "obr", remote.toURI().toString() );
+ try
+ {
+ // a missing remote file is returned as a non-existent file
+ File missing = manager.get( "repository.xml", ".xml" );
+ assertFalse( missing.exists() );
+
+ manager.lockFile( "repository.xml", false );
+ assertEquals( "LOCKED", new String( Files.readAllBytes( new File( remote, "repository.xml.lock" ).toPath() ),
+ StandardCharsets.UTF_8 ) );
+ assertTrue( manager.isLockedFile( "repository.xml" ) );
+
+ File local = tmp.newFile( "local.xml" );
+ Files.write( local.toPath(), "".getBytes( StandardCharsets.UTF_8 ) );
+ manager.put( local, "repository.xml" );
+ File downloaded = manager.get( "repository.xml", ".xml" );
+ assertEquals( "", new String( Files.readAllBytes( downloaded.toPath() ), StandardCharsets.UTF_8 ) );
+ downloaded.delete();
+
+ manager.unlockFile( "repository.xml" );
+ assertFalse( manager.isLockedFile( "repository.xml" ) );
+ assertTrue( manager.toString(), manager.toString().endsWith( "/obr" ) || manager.toString().endsWith( "/obr/" ) );
+ }
+ finally
+ {
+ manager.disconnect();
+ }
+
+ assertEquals( Collections.singletonList( "file" ), lookedUp );
+ assertEquals( 1, released.get() );
+
+ // disconnecting twice does not release the wagon twice
+ manager.disconnect();
+ assertEquals( 1, released.get() );
+ }
+}