QPID-8440: [JMS AMQP 0-x] Add support for user user defined extensions to override client settings
diff --git a/client/src/main/java/org/apache/qpid/client/AMQConnection.java b/client/src/main/java/org/apache/qpid/client/AMQConnection.java
index 4426fb6..7514ff8 100644
--- a/client/src/main/java/org/apache/qpid/client/AMQConnection.java
+++ b/client/src/main/java/org/apache/qpid/client/AMQConnection.java
@@ -151,12 +151,6 @@
private String _clientName;
- /** The user name to use for authentication */
- private String _username;
-
- /** The password to use for authentication */
- private String _password;
-
/** The virtual path to connect to on the AMQ server */
private String _virtualHost;
@@ -482,8 +476,6 @@
_connectionURL = connectionURL;
_clientName = connectionURL.getClientName();
- _username = connectionURL.getUsername();
- _password = connectionURL.getPassword();
setVirtualHost(connectionURL.getVirtualHost());
@@ -1356,17 +1348,17 @@
public String getUsername()
{
- return _username;
+ return _connectionURL.getUsername();
}
public void setUsername(String id)
{
- _username = id;
+ _connectionURL.setUsername(id);
}
public String getPassword()
{
- return _password;
+ return _connectionURL.getPassword();
}
public String getVirtualHost()
diff --git a/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java b/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
index ba3e4ae..c2e8c34 100644
--- a/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
+++ b/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_0_10.java
@@ -240,7 +240,11 @@
_qpidConnection.connect(conSettings);
_conn.setConnected(true);
- _conn.setUsername(_qpidConnection.getUserID());
+
+ if (_qpidConnection.getUserID() != null)
+ {
+ _conn.setUsername(_qpidConnection.getUserID());
+ }
_conn.setMaximumChannelCount(_qpidConnection.getChannelMax());
_conn.getFailoverPolicy().attainedConnection();
_conn.logConnected(_qpidConnection.getLocalAddress(), _qpidConnection.getRemoteSocketAddress());
diff --git a/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java b/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java
index a843f8f..066535f 100644
--- a/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java
+++ b/client/src/main/java/org/apache/qpid/client/AMQConnectionFactory.java
@@ -54,7 +54,8 @@
import java.util.UUID;
-public class AMQConnectionFactory implements ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory,
+public class AMQConnectionFactory extends AbstractConnectionFactory
+ implements ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory,
javax.naming.spi.ObjectFactory, Referenceable, XATopicConnectionFactory,
XAQueueConnectionFactory, XAConnectionFactory, Serializable
{
@@ -129,7 +130,7 @@
{
_connectionDetails.setClientName(getUniqueClientID());
}
- return new AMQConnection(_connectionDetails);
+ return newAMQConnectionInstance(_connectionDetails);
}
catch (Exception e)
{
@@ -161,7 +162,7 @@
{
connectionDetails.setClientName(getUniqueClientID());
}
- return new AMQConnection(connectionDetails);
+ return newAMQConnectionInstance(connectionDetails);
}
catch (Exception e)
{
diff --git a/client/src/main/java/org/apache/qpid/client/AbstractConnectionFactory.java b/client/src/main/java/org/apache/qpid/client/AbstractConnectionFactory.java
new file mode 100644
index 0000000..ea7549b
--- /dev/null
+++ b/client/src/main/java/org/apache/qpid/client/AbstractConnectionFactory.java
@@ -0,0 +1,74 @@
+/*
+ * 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.qpid.client;
+
+import java.net.URI;
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.function.BiFunction;
+
+import javax.jms.Connection;
+
+import org.apache.qpid.QpidException;
+import org.apache.qpid.jms.ConnectionURL;
+
+public abstract class AbstractConnectionFactory
+{
+ private final Map<ConnectionExtension, BiFunction<Connection, URI, Object>>
+ _extensions = new EnumMap<>(ConnectionExtension.class);
+
+
+ public void setExtension(String extensionName, BiFunction<Connection, URI, Object> extension)
+ {
+ final ConnectionExtension connectionExtension = ConnectionExtension.fromString(extensionName);
+ if (extension == null)
+ {
+ _extensions.remove(connectionExtension);
+ }
+ else
+ {
+ _extensions.put(connectionExtension, extension);
+ }
+ }
+
+ protected CommonConnection newConnectionInstance(final ConnectionURL connectionDetails) throws QpidException
+ {
+ return newAMQConnectionInstance(connectionDetails);
+ }
+
+ protected Map<ConnectionExtension, BiFunction<Connection, URI, Object>> getExtensions()
+ {
+ return new EnumMap<>(_extensions);
+ }
+
+ final AMQConnection newAMQConnectionInstance(final ConnectionURL connectionDetails) throws QpidException
+ {
+ final Map<ConnectionExtension, BiFunction<Connection, URI, Object>> extensions = getExtensions();
+ final ConnectionURL connectionURL =
+ extensions.isEmpty() ? connectionDetails : new ExtensibleConnectionURL(connectionDetails, extensions);
+ final AMQConnection connection = new AMQConnection(connectionURL);
+ if (connectionURL instanceof ExtensibleConnectionURL)
+ {
+ ((ExtensibleConnectionURL) connectionURL).setConnectionSupplier(() -> connection);
+ }
+ return connection;
+ }
+}
diff --git a/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java b/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
index 12fa91f..cba727b 100644
--- a/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
+++ b/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java
@@ -193,6 +193,10 @@
{
declareDestination(_destination);
}
+ if (_connection.isPopulateUserId())
+ {
+ _userID = _connection.getUsername();
+ }
}
abstract void declareDestination(AMQDestination destination) throws QpidException;
diff --git a/client/src/main/java/org/apache/qpid/client/ConnectionExtension.java b/client/src/main/java/org/apache/qpid/client/ConnectionExtension.java
new file mode 100644
index 0000000..364a24a
--- /dev/null
+++ b/client/src/main/java/org/apache/qpid/client/ConnectionExtension.java
@@ -0,0 +1,51 @@
+/*
+ * 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.qpid.client;
+
+public enum ConnectionExtension
+{
+ USERNAME_OVERRIDE("username"),
+ PASSWORD_OVERRIDE("password");
+
+ private final String _extensionName;
+
+ ConnectionExtension(final String extensionName)
+ {
+ _extensionName = extensionName;
+ }
+
+ public String getExtensionName()
+ {
+ return _extensionName;
+ }
+
+ public static ConnectionExtension fromString(String name)
+ {
+ for (ConnectionExtension extension : ConnectionExtension.values())
+ {
+ if (extension.getExtensionName().equalsIgnoreCase(name) || extension.name().equalsIgnoreCase(name))
+ {
+ return extension;
+ }
+ }
+ throw new IllegalArgumentException(String.format("Extension with name '%s' is not found", name));
+ }
+}
diff --git a/client/src/main/java/org/apache/qpid/client/ExtensibleConnectionURL.java b/client/src/main/java/org/apache/qpid/client/ExtensibleConnectionURL.java
new file mode 100644
index 0000000..1523bf6
--- /dev/null
+++ b/client/src/main/java/org/apache/qpid/client/ExtensibleConnectionURL.java
@@ -0,0 +1,229 @@
+/*
+ * 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.qpid.client;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.Supplier;
+
+import javax.jms.Connection;
+
+import org.apache.qpid.QpidException;
+import org.apache.qpid.jms.ConnectionURL;
+
+public class ExtensibleConnectionURL implements ConnectionURL
+{
+ private final ConnectionURL _connectionURL;
+ private final Map<ConnectionExtension, BiFunction<Connection, URI, Object>> _extensions;
+ private final URI _connectionURI;
+ private volatile Supplier<AMQConnection> _connectionSupplier;
+
+ ExtensibleConnectionURL(final ConnectionURL connectionURL,
+ final Map<ConnectionExtension, BiFunction<Connection, URI, Object>> extensions)
+ throws QpidException
+ {
+ this(connectionURL, extensions, () -> null);
+ }
+
+ ExtensibleConnectionURL(final ConnectionURL connectionURL,
+ final Map<ConnectionExtension, BiFunction<Connection, URI, Object>> extensions,
+ final Supplier<AMQConnection> connectionSupplier) throws QpidException
+ {
+ _connectionURL = connectionURL;
+ _extensions = extensions;
+ _connectionSupplier = connectionSupplier;
+
+ try
+ {
+ _connectionURI = new URI(_connectionURL.getURL());
+ }
+ catch (URISyntaxException e)
+ {
+ throw new QpidException("Unexpected connection URL", e);
+ }
+ }
+
+ @Override
+ public String getURL()
+ {
+ return _connectionURL.getURL();
+ }
+
+ @Override
+ public String getFailoverMethod()
+ {
+ return _connectionURL.getFailoverMethod();
+ }
+
+ @Override
+ public String getFailoverOption(final String key)
+ {
+ return _connectionURL.getFailoverOption(key);
+ }
+
+ @Override
+ public int getBrokerCount()
+ {
+ return _connectionURL.getBrokerCount();
+ }
+
+ @Override
+ public BrokerDetails getBrokerDetails(final int index)
+ {
+ return _connectionURL.getBrokerDetails(index);
+ }
+
+ @Override
+ public void addBrokerDetails(final BrokerDetails broker)
+ {
+ _connectionURL.addBrokerDetails(broker);
+ }
+
+ @Override
+ public void setBrokerDetails(final List<BrokerDetails> brokers)
+ {
+ _connectionURL.setBrokerDetails(brokers);
+ }
+
+ @Override
+ public List<BrokerDetails> getAllBrokerDetails()
+ {
+ return _connectionURL.getAllBrokerDetails();
+ }
+
+ @Override
+ public String getClientName()
+ {
+ return _connectionURL.getClientName();
+ }
+
+ @Override
+ public void setClientName(final String clientName)
+ {
+ _connectionURL.setClientName(clientName);
+ }
+
+ @Override
+ public String getUsername()
+ {
+ if (_extensions.containsKey(ConnectionExtension.USERNAME_OVERRIDE))
+ {
+ final BiFunction<Connection, URI, Object> extension =
+ _extensions.get(ConnectionExtension.USERNAME_OVERRIDE);
+ final Object userName = extension.apply(_connectionSupplier.get(), _connectionURI);
+ return userName == null ? null : String.valueOf(userName);
+ }
+ else
+ {
+ return _connectionURL.getUsername();
+ }
+ }
+
+ @Override
+ public void setUsername(final String username)
+ {
+ _connectionURL.setUsername(username);
+ }
+
+ @Override
+ public String getPassword()
+ {
+ if (_extensions.containsKey(ConnectionExtension.PASSWORD_OVERRIDE))
+ {
+ final BiFunction<Connection, URI, Object> extension =
+ _extensions.get(ConnectionExtension.PASSWORD_OVERRIDE);
+ final Object password = extension.apply(_connectionSupplier.get(), _connectionURI);
+ return password == null ? null : String.valueOf(password);
+ }
+ else
+ {
+ return _connectionURL.getPassword();
+ }
+ }
+
+ @Override
+ public void setPassword(final String password)
+ {
+ _connectionURL.setPassword(password);
+ }
+
+ @Override
+ public String getVirtualHost()
+ {
+ return _connectionURL.getVirtualHost();
+ }
+
+ @Override
+ public void setVirtualHost(final String virtualHost)
+ {
+ _connectionURL.setVirtualHost(virtualHost);
+ }
+
+ @Override
+ public String getOption(final String key)
+ {
+ return _connectionURL.getOption(key);
+ }
+
+ @Override
+ public void setOption(final String key, final String value)
+ {
+ _connectionURL.setOption(key, value);
+ }
+
+ @Override
+ public String getDefaultQueueExchangeName()
+ {
+ return _connectionURL.getDefaultQueueExchangeName();
+ }
+
+ @Override
+ public String getDefaultTopicExchangeName()
+ {
+ return _connectionURL.getDefaultTopicExchangeName();
+ }
+
+ @Override
+ public String getTemporaryQueueExchangeName()
+ {
+ return _connectionURL.getTemporaryQueueExchangeName();
+ }
+
+ @Override
+ public String getTemporaryTopicExchangeName()
+ {
+ return _connectionURL.getTemporaryTopicExchangeName();
+ }
+
+ @Override
+ public String toString()
+ {
+ return _connectionURL.toString();
+ }
+
+ void setConnectionSupplier(final Supplier<AMQConnection> connectionSupplier)
+ {
+ _connectionSupplier = connectionSupplier;
+ }
+}
diff --git a/client/src/main/java/org/apache/qpid/client/PooledConnectionFactory.java b/client/src/main/java/org/apache/qpid/client/PooledConnectionFactory.java
index 0f41ab0..abf6fba 100644
--- a/client/src/main/java/org/apache/qpid/client/PooledConnectionFactory.java
+++ b/client/src/main/java/org/apache/qpid/client/PooledConnectionFactory.java
@@ -64,8 +64,8 @@
import org.apache.qpid.jms.*;
import org.apache.qpid.url.URLSyntaxException;
-public class PooledConnectionFactory implements ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory,
- Referenceable
+public class PooledConnectionFactory extends AbstractConnectionFactory
+ implements ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory, Referenceable
{
public static final String JNDI_ADDRESS_MAX_POOL_SIZE = "maxPoolSize";
@@ -262,11 +262,6 @@
}
}
- protected CommonConnection newConnectionInstance(final ConnectionURL connectionDetails) throws QpidException
- {
- return new AMQConnection(connectionDetails);
- }
-
private ConnectionURL getConnectionURLOrError() throws IllegalStateException
{
final ConnectionURL connectionDetails = _connectionDetails.get();
diff --git a/client/src/main/java/org/apache/qpid/transport/Connection.java b/client/src/main/java/org/apache/qpid/transport/Connection.java
index 13289f1..f270665 100644
--- a/client/src/main/java/org/apache/qpid/transport/Connection.java
+++ b/client/src/main/java/org/apache/qpid/transport/Connection.java
@@ -223,7 +223,6 @@
conSettings = settings;
_redirecting.set(false);
state = OPENING;
- userID = settings.getUsername();
connectionLost.set(false);
securityLayer = SecurityLayerFactory.newInstance(getConnectionSettings());
diff --git a/doc/jms-client-0-8/src/docbkx/JMS-Client-JMS-Extensions.xml b/doc/jms-client-0-8/src/docbkx/JMS-Client-JMS-Extensions.xml
index e2a7732..431eb8a 100644
--- a/doc/jms-client-0-8/src/docbkx/JMS-Client-JMS-Extensions.xml
+++ b/doc/jms-client-0-8/src/docbkx/JMS-Client-JMS-Extensions.xml
@@ -22,7 +22,7 @@
<appendix xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="JMS-Client-0-8-Appendix-JMS-Extensions">
<title>JMS Extensions</title>
- <para>This section illustrates using Qpid specific extentions to JMS for the managament of queues,
+ <para>This section illustrates using Qpid specific extensions to JMS for the management of connections, queues,
exchanges and bindings.</para>
<!-- TODO perhaps mention ConnectionListener?-->
<important>
@@ -30,6 +30,104 @@
subject to change and will not be supported in this form for AMQP 1.0. Instead, the reader is
directed towards the Managment interfaces of the Broker.</para>
</important>
+ <section xml:id="JMS-Client-0-8-Appendix-JMS-Extensions-Connection">
+ <title>Connection extensions</title>
+ <para>Connection extensions allows overriding connection configurations like username or password
+ in response to some environment changes like account rotation or authentication token expiration.</para>
+ <para>
+ The extensions take the form of a BiFunction<Connection, URI, Object> passed into the
+ ConnectionFactory using the AMQConnectionFactory#setExtension(String, BiFunction).
+ </para>
+ <para>A table below lists supported extensions.</para>
+ <table pgwide="1">
+ <title>Connection Extensions</title>
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>Extension Name</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>username</entry>
+ <entry><para>Allows to hook a custom code for provisioning of user name which would be used in authentication
+ with a remote host.</para></entry>
+ </row>
+ <row>
+ <entry>password</entry>
+ <entry><para>Allows to hook a custom code for provisioning of user password which would be used in
+ authentication with a remote host.</para></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>The following example illustrates how expirate OAUTH2 authentication token can be recreated</para>
+ <example>
+ <title>Inject password extension</title>
+ <programlisting>
+final String connectionURL = "..."; <co xml:id="ext-token-url" linkends="callout-ext-token-url"/>
+final TokenGenerator tokenGenerator = new TokenGenerator(...); <co xml:id="ext-token-generator" linkends="callout-ext-token-generator"/>
+
+final BiFunction<Connection, URI, Object> tokenExtension = new BiFunction<Connection, URI, Object>() <co xml:id="ext-token-extension" linkends="callout-ext-token-extension"/>
+{
+ private volatile String token;
+ private long currentTokenExpirationTime;
+
+ @Override
+ public Object apply(final Connection connection, final URI uri)
+ {
+ long currentTime = System.currentTimeMillis();
+ if (currentTime > currentTokenExpirationTime) <co xml:id="ext-token-expiration-check" linkends="callout-ext-token-expiration-check"/>
+ {
+ this.token = tokenGenerator.generateAccessToken(); <co xml:id="ext-token-generation" linkends="callout-ext-token-generation"/>
+ this.currentTokenExpirationTime = tokenGenerator.getTokenExpirationTime(token); <co xml:id="ext-token-exp-time" linkends="callout-ext-token-exp-time"/>
+ }
+ return this.token;
+ }
+};
+final AMQConnectionFactory factory = new AMQConnectionFactory(connectionURL); <co xml:id="ext-token-connection-factory" linkends="callout-ext-token-connection-factory"/>
+factory.setExtension(ConnectionExtension.PASSWORD_OVERRIDE.name(), tokenExtension); <co xml:id="ext-token-override" linkends="callout-ext-token-override"/>
+
+final Connection connection = factory.createConnection(); <co xml:id="ext-token-connection" linkends="callout-ext-token-connection"/>
+ </programlisting>
+ </example><calloutlist>
+ <callout xml:id="callout-ext-token-url" arearefs="ext-token-url">
+ <para>Connection URL</para>
+ </callout>
+ <callout xml:id="callout-ext-token-generator" arearefs="ext-token-generator">
+ <para>Helper object to generate access token for a specific OAUTH2 implementation </para>
+ </callout>
+ <callout xml:id="callout-ext-token-extension" arearefs="ext-token-extension">
+ <para>Password extension for token renewal</para>
+ </callout>
+ <callout xml:id="callout-ext-token-expiration-check" arearefs="ext-token-expiration-check">
+ <para>Check token expiration</para>
+ </callout>
+ <callout xml:id="callout-ext-token-generation" arearefs="ext-token-generation">
+ <para>Get new token</para>
+ </callout>
+ <callout xml:id="callout-ext-token-exp-time" arearefs="ext-token-exp-time">
+ <para>Preserve token expiration time</para>
+ </callout>
+ <callout xml:id="callout-ext-token-connection-factory" arearefs="ext-token-connection-factory">
+ <para>Create connection factory</para>
+ </callout>
+ <callout xml:id="callout-ext-token-override" arearefs="ext-token-override">
+ <para>Register password extension for token regeneration</para>
+ </callout>
+ <callout xml:id="callout-ext-token-connection" arearefs="ext-token-connection">
+ <para>Open connection</para>
+ </callout>
+ </calloutlist>
+ <para>In the snippet above an implementation of BiFunction<Connection, URI, Object> is created at (3) for
+ access token provisioning. The function implementation checks the token expiration at (4) and regenerate
+ the token at (5) using a helper object (2) implementing calls to OAUTH2 specific API.
+ The token expiration time is preserved at (6) for the following reconnects attempts.
+ An instance of AMQConnectionFactory is created at (7) for a given connection URL (1).
+ A password extension is registered at (8). JMS connection is open at (9). The example uses a hypothetical
+ class TokenGenerator invoking underlying OAUTH2 API to generate/renew access token and get token expiration time.</para>
+ </section>
<section xml:id="JMS-Client-0-8-Appendix-JMS-Extensions-Queue">
<title>Queue Management</title>
<para>These extensions allow queues to be created or removed.</para>
diff --git a/systests/src/test/java/org/apache/qpid/systest/connection/ConnectionFactoryTest.java b/systests/src/test/java/org/apache/qpid/systest/connection/ConnectionFactoryTest.java
index c9eb034..e5db8ee 100644
--- a/systests/src/test/java/org/apache/qpid/systest/connection/ConnectionFactoryTest.java
+++ b/systests/src/test/java/org/apache/qpid/systest/connection/ConnectionFactoryTest.java
@@ -21,47 +21,54 @@
package org.apache.qpid.systest.connection;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
import java.net.InetSocketAddress;
-import javax.jms.Connection;
+import javax.jms.JMSException;
import org.junit.Before;
import org.junit.Test;
import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.ConnectionExtension;
import org.apache.qpid.systest.core.BrokerAdmin;
import org.apache.qpid.systest.core.JmsTestBase;
public class ConnectionFactoryTest extends JmsTestBase
{
- private static final String CONNECTION_URL = "amqp://guest:guest@clientID/?brokerlist='tcp://%s:%d'";
- private String _url;
+ private static final String CONNECTION_URL = "amqp://%s:%s@clientID/?brokerlist='tcp://%s:%d'";
+ private String _urlWithCredentials;
+ private String _urlWithoutCredentials;
+ private String _userName;
+ private String _password;
@Before
public void setUp()
{
- final InetSocketAddress brokerAddress = getBrokerAdmin().getBrokerAddress(BrokerAdmin.PortType.AMQP);
- _url = String.format(CONNECTION_URL,
- brokerAddress.getHostString(),
- brokerAddress.getPort());
+ final BrokerAdmin brokerAdmin = getBrokerAdmin();
+ final InetSocketAddress brokerAddress = brokerAdmin.getBrokerAddress(BrokerAdmin.PortType.AMQP);
+ _userName = brokerAdmin.getValidUsername();
+ _password = brokerAdmin.getValidPassword();
+ final String host = brokerAddress.getHostString();
+ final int port = brokerAddress.getPort();
+ _urlWithCredentials = String.format(CONNECTION_URL, _userName, _password, host, port);
+ _urlWithoutCredentials = String.format(CONNECTION_URL, "", "", host, port);
}
- /**
- * The username & password specified should not override the default
- * specified in the URL.
- */
+
@Test
- public void testCreateConnectionWithUsernamePassword() throws Exception
+ public void testCreateConnectionWithUsernamePasswordSetOnConnectionURL() throws Exception
{
- AMQConnectionFactory factory = new AMQConnectionFactory(_url);
+ AMQConnectionFactory factory = new AMQConnectionFactory(_urlWithCredentials);
AMQConnection con = null;
try
{
con = factory.createConnection();
- assertEquals("Usernames used is different from the one in URL","guest",con.getConnectionURL().getUsername());
- assertEquals("Password used is different from the one in URL","guest",con.getConnectionURL().getPassword());
+ assertEquals("Usernames used is different from the one in URL", _userName, con.getUsername());
+ assertEquals("Password used is different from the one in URL", _password, con.getPassword());
}
finally
{
@@ -70,17 +77,18 @@
con.close();
}
}
+ }
+ @Test
+ public void testCreateConnectionWithUsernamePasswordPassedIntoCreateConnection() throws Exception
+ {
+ AMQConnectionFactory factory = new AMQConnectionFactory(_urlWithCredentials);
AMQConnection con2 = null;
try
{
- con2 = factory.createConnection("user", "pass");
- assertEquals("Usernames used is different from the one in URL","user",con2.getConnectionURL().getUsername());
- assertEquals("Password used is different from the one in URL","pass",con2.getConnectionURL().getPassword());
- }
- catch(Exception e)
- {
- // ignore
+ con2 = factory.createConnection("admin", "admin");
+ assertEquals("Usernames used is different from the one in URL", "admin", con2.getUsername());
+ assertEquals("Password used is different from the one in URL", "admin", con2.getPassword());
}
finally
{
@@ -89,13 +97,20 @@
con2.close();
}
}
+ }
+
+ @Test
+ public void testCreateConnectionWithUsernamePasswordPassedIntoCreateConnectionWhenConnectionUrlWithoutCredentials()
+ throws Exception
+ {
+ AMQConnectionFactory factory = new AMQConnectionFactory(_urlWithoutCredentials);
AMQConnection con3 = null;
try
{
- con3 = factory.createConnection();
- assertEquals("Usernames used is different from the one in URL","guest",con3.getConnectionURL().getUsername());
- assertEquals("Password used is different from the one in URL","guest",con3.getConnectionURL().getPassword());
+ con3 = factory.createConnection(_userName, _password);
+ assertEquals("Usernames used is different from the one in URL", _userName, con3.getUsername());
+ assertEquals("Password used is different from the one in URL", _password, con3.getPassword());
}
finally
{
@@ -106,20 +121,73 @@
}
}
- /**
- * Verifies that a connection can be made using an instance of AMQConnectionFactory created with the
- * default constructor and provided with the connection url via setter.
- */
@Test
public void testCreatingConnectionWithInstanceMadeUsingDefaultConstructor() throws Exception
{
AMQConnectionFactory factory = new AMQConnectionFactory();
- factory.setConnectionURLString(_url);
+ factory.setConnectionURLString(_urlWithCredentials);
- Connection con = null;
+ AMQConnection con = null;
try
{
con = factory.createConnection();
+ assertNotNull(con);
+ assertEquals(_userName, con.getUsername());
+ assertEquals(_password, con.getPassword());
+ }
+ finally
+ {
+ if (con != null)
+ {
+ con.close();
+ }
+ }
+ }
+
+ @Test
+ public void testCreatingConnectionUsingUserNameAndPasswordExtensions() throws Exception
+ {
+ AMQConnectionFactory factory = new AMQConnectionFactory();
+ factory.setConnectionURLString(_urlWithoutCredentials);
+ factory.setExtension(ConnectionExtension.PASSWORD_OVERRIDE.getExtensionName(), (connection, uri) -> _password);
+ factory.setExtension(ConnectionExtension.USERNAME_OVERRIDE.getExtensionName(), (connection, uri) -> _userName);
+
+ AMQConnection con = null;
+ try
+ {
+ con = factory.createConnection();
+ assertNotNull(con);
+ assertEquals(_userName, con.getUsername());
+ assertEquals(_password, con.getPassword());
+ }
+ finally
+ {
+ if (con != null)
+ {
+ con.close();
+ }
+ }
+ }
+
+ @Test
+ public void testCreatingConnectionUsingUserNameAndPasswordExtensionsWhenRuntimeExceptionIsThrown() throws Exception
+ {
+ AMQConnectionFactory factory = new AMQConnectionFactory();
+ factory.setConnectionURLString(_urlWithoutCredentials);
+ factory.setExtension(ConnectionExtension.PASSWORD_OVERRIDE.getExtensionName(), (connection, uri) -> {
+ throw new RuntimeException("Test");
+ });
+ factory.setExtension(ConnectionExtension.USERNAME_OVERRIDE.getExtensionName(), (connection, uri) -> _userName);
+
+ AMQConnection con = null;
+ try
+ {
+ con = factory.createConnection();
+ fail("Exception is expected");
+ }
+ catch (JMSException e)
+ {
+ // pass
}
finally
{