You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by or...@apache.org on 2019/05/08 19:58:59 UTC

[qpid-broker-j] branch master updated (2a85e19 -> 6dc4f78)

This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git.


    from 2a85e19  QPID-8309: [Broker-J] Fix local transaction discharge when async underlying store transaction is in progress
     new ce1cb00  QPID-8306: [Broker-J] Add operation to update port TLS support
     new 6dc4f78  QPID-8307:[Broker-J][Documentation] Document how to specify virtualhost initial configuration

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../java/org/apache/qpid/server/model/Port.java    |  13 +
 .../qpid/server/model/port/AbstractPort.java       |  18 +
 .../apache/qpid/server/model/port/AmqpPort.java    |   4 -
 .../qpid/server/model/port/AmqpPortImpl.java       |  16 +-
 .../qpid/server/model/port/HttpPortImpl.java       |  37 +-
 .../apache/qpid/server/model/port/PortManager.java |   6 +
 .../qpid/server/transport/AcceptingTransport.java  |   2 +
 .../transport/NonBlockingNetworkTransport.java     |   7 +-
 .../qpid/server/transport/TCPandSSLTransport.java  |  35 +-
 .../server/management/plugin/HttpManagement.java   | 114 ++++--
 .../main/java/resources/js/qpid/management/Port.js |  28 ++
 .../src/main/java/resources/showPort.html          |   1 +
 .../transport/websocket/WebSocketProvider.java     |  81 +++--
 .../docbkx/Java-Broker-Initial-Configuration.xml   |  36 +-
 .../Java-Broker-Concepts-Virtualhost-Nodes.xml     |   5 +
 .../qpid/tests/http/endtoend/port/PortTest.java    | 400 +++++++++++++++++++++
 .../apache/qpid/systests/ConnectionBuilder.java    |   2 +
 .../systests/QpidJmsClient0xConnectionBuilder.java |   8 +-
 .../systests/QpidJmsClientConnectionBuilder.java   |  14 +-
 19 files changed, 741 insertions(+), 86 deletions(-)
 create mode 100644 systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/endtoend/port/PortTest.java


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-broker-j] 01/02: QPID-8306: [Broker-J] Add operation to update port TLS support

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git

commit ce1cb00c795a70ed33f8717250f0ab61838d23f5
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Tue Apr 30 13:26:24 2019 +0100

    QPID-8306: [Broker-J] Add operation to update port TLS support
    
    This closes #31
---
 .../java/org/apache/qpid/server/model/Port.java    |  13 +
 .../qpid/server/model/port/AbstractPort.java       |  18 +
 .../apache/qpid/server/model/port/AmqpPort.java    |   4 -
 .../qpid/server/model/port/AmqpPortImpl.java       |  16 +-
 .../qpid/server/model/port/HttpPortImpl.java       |  37 +-
 .../apache/qpid/server/model/port/PortManager.java |   6 +
 .../qpid/server/transport/AcceptingTransport.java  |   2 +
 .../transport/NonBlockingNetworkTransport.java     |   7 +-
 .../qpid/server/transport/TCPandSSLTransport.java  |  35 +-
 .../server/management/plugin/HttpManagement.java   | 114 ++++--
 .../main/java/resources/js/qpid/management/Port.js |  28 ++
 .../src/main/java/resources/showPort.html          |   1 +
 .../transport/websocket/WebSocketProvider.java     |  81 +++--
 .../qpid/tests/http/endtoend/port/PortTest.java    | 400 +++++++++++++++++++++
 .../apache/qpid/systests/ConnectionBuilder.java    |   2 +
 .../systests/QpidJmsClient0xConnectionBuilder.java |   8 +-
 .../systests/QpidJmsClientConnectionBuilder.java   |  14 +-
 17 files changed, 705 insertions(+), 81 deletions(-)

diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Port.java b/broker-core/src/main/java/org/apache/qpid/server/model/Port.java
index 3850afd..510d4d5 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Port.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Port.java
@@ -24,6 +24,8 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 
+import javax.net.ssl.SSLContext;
+
 import com.google.common.util.concurrent.ListenableFuture;
 
 import org.apache.qpid.server.configuration.CommonProperties;
@@ -105,6 +107,8 @@ public interface Port<X extends Port<X>> extends ConfiguredObject<X>
                                     + "hostname.  If null or * then bind to all interfaces.")
     String getBindingAddress();
 
+    SSLContext getSSLContext();
+
     @ManagedAttribute
     boolean getNeedClientAuth();
 
@@ -133,5 +137,14 @@ public interface Port<X extends Port<X>> extends ConfiguredObject<X>
 
     SubjectCreator getSubjectCreator(final boolean secure, String host);
 
+    @DerivedAttribute(description = "Indicates whether TLS transport support is created.")
+    boolean isTlsSupported();
 
+    @ManagedOperation(description =
+            "Updates port TLS support without affecting existing connections."
+            + " The TLS changes are applied to new connections only."
+            + " Returns true if TLS support is successfully updated.",
+            nonModifying = true,
+            changesConfiguredObjectState = false)
+    boolean updateTLS();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java b/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java
index 45efb41..a5fb3d2 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java
@@ -504,4 +504,22 @@ public abstract class AbstractPort<X extends AbstractPort<X>> extends AbstractCo
         return getCategoryClass().getSimpleName() + "[id=" + getId() + ", name=" + getName() + ", type=" + getType() +  ", port=" + getPort() + "]";
     }
 
+    @Override
+    public boolean isTlsSupported()
+    {
+        return getSSLContext() != null;
+    }
+
+    @Override
+    public boolean updateTLS()
+    {
+        if (isTlsSupported())
+        {
+            return updateSSLContext();
+        }
+        return false;
+    }
+
+    protected abstract boolean updateSSLContext();
+
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java b/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java
index c1144d1..f88b99a 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java
@@ -24,8 +24,6 @@ import java.net.SocketAddress;
 import java.util.List;
 import java.util.Set;
 
-import javax.net.ssl.SSLContext;
-
 import org.apache.qpid.server.model.DerivedAttribute;
 import org.apache.qpid.server.model.ManagedAttribute;
 import org.apache.qpid.server.model.ManagedContextDefault;
@@ -132,8 +130,6 @@ public interface AmqpPort<X extends AmqpPort<X>> extends Port<X>
             description = "The connection property enrichers to apply to connections created on this port.")
     String DEFAULT_CONNECTION_PROTOCOL_ENRICHERS = "[ \"STANDARD\" ] ";
 
-    SSLContext getSSLContext();
-
     @ManagedAttribute( defaultValue = AmqpPort.DEFAULT_AMQP_TCP_NO_DELAY )
     boolean isTcpNoDelay();
 
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java b/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java
index 4e4fc64..88fc19c 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java
@@ -98,8 +98,8 @@ public class AmqpPortImpl extends AbstractPort<AmqpPortImpl> implements AmqpPort
     private final Container<?> _container;
     private final AtomicBoolean _closingOrDeleting = new AtomicBoolean();
 
-    private AcceptingTransport _transport;
-    private SSLContext _sslContext;
+    private volatile AcceptingTransport _transport;
+    private volatile SSLContext _sslContext;
     private volatile int _connectionWarnCount;
     private volatile long _protocolHandshakeTimeout;
     private volatile int _boundPort = -1;
@@ -275,6 +275,18 @@ public class AmqpPortImpl extends AbstractPort<AmqpPortImpl> implements AmqpPort
     }
 
     @Override
+    protected boolean updateSSLContext()
+    {
+        final Set<Transport> transports = getTransports();
+        if (transports.contains(Transport.SSL) || transports.contains(Transport.WSS))
+        {
+            _sslContext = createSslContext();
+            return _transport.updatesSSLContext();
+        }
+        return false;
+    }
+
+    @Override
     protected ListenableFuture<Void> beforeClose()
     {
         _closingOrDeleting.set(true);
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortImpl.java b/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortImpl.java
index 21b4c26..a3d714d 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortImpl.java
@@ -23,12 +23,15 @@ package org.apache.qpid.server.model.port;
 import java.util.Map;
 import java.util.Set;
 
+import javax.net.ssl.SSLContext;
+
 import org.apache.qpid.server.configuration.IllegalConfigurationException;
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.Container;
 import org.apache.qpid.server.model.ManagedAttributeField;
 import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
 import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.Transport;
 
 public class HttpPortImpl extends AbstractPort<HttpPortImpl> implements HttpPort<HttpPortImpl>
 {
@@ -66,7 +69,8 @@ public class HttpPortImpl extends AbstractPort<HttpPortImpl> implements HttpPort
     @Override
     public int getBoundPort()
     {
-        return _portManager == null ? -1 : _portManager.getBoundPort(this);
+        final PortManager portManager = getPortManager();
+        return portManager == null ? -1 : portManager.getBoundPort(this);
     }
 
     @Override
@@ -108,13 +112,15 @@ public class HttpPortImpl extends AbstractPort<HttpPortImpl> implements HttpPort
     @Override
     public int getNumberOfAcceptors()
     {
-        return _portManager == null ? 0 : _portManager.getNumberOfAcceptors(this) ;
+        final PortManager portManager = getPortManager();
+        return portManager == null ? 0 : portManager.getNumberOfAcceptors(this) ;
     }
 
     @Override
     public int getNumberOfSelectors()
     {
-        return _portManager == null ? 0 : _portManager.getNumberOfSelectors(this) ;
+        final PortManager portManager = getPortManager();
+        return portManager == null ? 0 : portManager.getNumberOfSelectors(this) ;
     }
 
     @Override
@@ -145,7 +151,7 @@ public class HttpPortImpl extends AbstractPort<HttpPortImpl> implements HttpPort
     @Override
     protected State onActivate()
     {
-        if(_portManager != null)
+        if(getPortManager() != null)
         {
             return super.onActivate();
         }
@@ -156,6 +162,29 @@ public class HttpPortImpl extends AbstractPort<HttpPortImpl> implements HttpPort
     }
 
     @Override
+    public SSLContext getSSLContext()
+    {
+        final PortManager portManager = getPortManager();
+        return portManager == null ? null : portManager.getSSLContext(this);
+    }
+
+    @Override
+    protected boolean updateSSLContext()
+    {
+        if (getTransports().contains(Transport.SSL))
+        {
+            final PortManager portManager = getPortManager();
+            return portManager != null && portManager.updateSSLContext(this);
+        }
+        return false;
+    }
+
+    private PortManager getPortManager()
+    {
+        return _portManager;
+    }
+
+    @Override
     public void onValidate()
     {
         super.onValidate();
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/port/PortManager.java b/broker-core/src/main/java/org/apache/qpid/server/model/port/PortManager.java
index b535a8b..3a06462 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/port/PortManager.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/port/PortManager.java
@@ -20,6 +20,8 @@
  */
 package org.apache.qpid.server.model.port;
 
+import javax.net.ssl.SSLContext;
+
 public interface PortManager
 {
     int getBoundPort(HttpPort httpPort);
@@ -27,4 +29,8 @@ public interface PortManager
     int getNumberOfAcceptors(HttpPort httpPort);
 
     int getNumberOfSelectors(HttpPort httpPort);
+
+    SSLContext getSSLContext(HttpPort httpPort);
+
+    boolean updateSSLContext(HttpPort httpPort);
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/AcceptingTransport.java b/broker-core/src/main/java/org/apache/qpid/server/transport/AcceptingTransport.java
index e8b7fda..bfefac1 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/transport/AcceptingTransport.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/AcceptingTransport.java
@@ -27,4 +27,6 @@ public interface AcceptingTransport
     void close();
 
     int getAcceptingPort();
+
+    boolean updatesSSLContext();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingNetworkTransport.java b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingNetworkTransport.java
index 02767f4..76f5977 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingNetworkTransport.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingNetworkTransport.java
@@ -42,7 +42,7 @@ public class NonBlockingNetworkTransport
 
     private static final Logger LOGGER = LoggerFactory.getLogger(NonBlockingNetworkTransport.class);
 
-    private final Set<TransportEncryption> _encryptionSet;
+    private volatile Set<TransportEncryption> _encryptionSet;
     private final MultiVersionProtocolEngineFactory _factory;
     private final ServerSocketChannel _serverSocket;
     private final NetworkConnectionScheduler _scheduler;
@@ -205,4 +205,9 @@ public class NonBlockingNetworkTransport
             }
         }
     }
+
+    void setEncryptionSet(final Set<TransportEncryption> encryptionSet)
+    {
+        _encryptionSet = encryptionSet;
+    }
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/TCPandSSLTransport.java b/broker-core/src/main/java/org/apache/qpid/server/transport/TCPandSSLTransport.java
index f52d50d..477d784 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/transport/TCPandSSLTransport.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/TCPandSSLTransport.java
@@ -32,7 +32,7 @@ import org.apache.qpid.server.transport.network.TransportEncryption;
 class TCPandSSLTransport implements AcceptingTransport
 {
     private NonBlockingNetworkTransport _networkTransport;
-    private Set<Transport> _transports;
+    private volatile Set<Transport> _transports;
     private AmqpPort<?> _port;
     private Set<Protocol> _supported;
     private Protocol _defaultSupportedProtocolReply;
@@ -60,15 +60,7 @@ class TCPandSSLTransport implements AcceptingTransport
                         _port,
                         _transports.contains(Transport.TCP) ? Transport.TCP : Transport.SSL);
 
-        EnumSet<TransportEncryption> encryptionSet = EnumSet.noneOf(TransportEncryption.class);
-        if(_transports.contains(Transport.TCP))
-        {
-            encryptionSet.add(TransportEncryption.NONE);
-        }
-        if(_transports.contains(Transport.SSL))
-        {
-            encryptionSet.add(TransportEncryption.TLS);
-        }
+        EnumSet<TransportEncryption> encryptionSet = buildEncryptionSet(_transports);
 
         long threadPoolKeepAliveTimeout = _port.getContextValue(Long.class, AmqpPort.PORT_AMQP_THREAD_POOL_KEEP_ALIVE_TIMEOUT);
 
@@ -80,6 +72,20 @@ class TCPandSSLTransport implements AcceptingTransport
         _networkTransport.start();
     }
 
+    private EnumSet<TransportEncryption> buildEncryptionSet(final Set<Transport> transports)
+    {
+        EnumSet<TransportEncryption> encryptionSet = EnumSet.noneOf(TransportEncryption.class);
+        if(transports.contains(Transport.TCP))
+        {
+            encryptionSet.add(TransportEncryption.NONE);
+        }
+        if(transports.contains(Transport.SSL))
+        {
+            encryptionSet.add(TransportEncryption.TLS);
+        }
+        return encryptionSet;
+    }
+
     @Override
     public int getAcceptingPort()
     {
@@ -88,6 +94,15 @@ class TCPandSSLTransport implements AcceptingTransport
     }
 
     @Override
+    public boolean updatesSSLContext()
+    {
+        Set<Transport> transports = _port.getTransports();
+        _transports = transports;
+        _networkTransport.setEncryptionSet(buildEncryptionSet(transports));
+        return true;
+    }
+
+    @Override
     public void close()
     {
         if (_networkTransport != null)
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
index b76ab9d..4fa87ed 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
@@ -181,6 +181,7 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem
     private boolean _compressResponses;
 
     private final Map<HttpPort<?>, ServerConnector> _portConnectorMap = new ConcurrentHashMap<>();
+    private final Map<HttpPort<?>, SslContextFactory> _sslContextFactoryMap = new ConcurrentHashMap<>();
     private final BrokerChangeListener _brokerChangeListener = new BrokerChangeListener();
 
     private volatile boolean _serveUncompressedDojo;
@@ -459,6 +460,46 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem
         }
     }
 
+    @Override
+    public SSLContext getSSLContext(final HttpPort httpPort)
+    {
+        final SslContextFactory sslContextFactory = getSslContextFactory(httpPort);
+        if ( sslContextFactory != null)
+        {
+            return sslContextFactory.getSslContext();
+        }
+        return null;
+    }
+
+    @Override
+    public boolean updateSSLContext(final HttpPort httpPort)
+    {
+        final SslContextFactory sslContextFactory = getSslContextFactory(httpPort);
+        if ( sslContextFactory != null)
+        {
+            try
+            {
+                final SSLContext sslContext = createSslContext(httpPort);
+                sslContextFactory.reload(f -> {
+                    f.setSslContext(sslContext);
+                    f.setNeedClientAuth(httpPort.getNeedClientAuth());
+                    f.setWantClientAuth(httpPort.getWantClientAuth());
+                });
+                return true;
+            }
+            catch (Exception e)
+            {
+                throw new IllegalConfigurationException("Unexpected exception on reload of ssl context factory", e);
+            }
+        }
+        return false;
+    }
+
+    private SslContextFactory getSslContextFactory(final HttpPort httpPort)
+    {
+        return _sslContextFactoryMap.get(httpPort);
+    }
+
     private ServerConnector createConnector(final HttpPort<?> port, final Server server)
     {
         port.setPortManager(this);
@@ -481,13 +522,14 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem
 
         ConnectionFactory[] connectionFactories;
         Collection<Transport> transports = port.getTransports();
+        SslContextFactory sslContextFactory = null;
         if (!transports.contains(Transport.SSL))
         {
             connectionFactories = new ConnectionFactory[]{httpConnectionFactory};
         }
         else if (transports.contains(Transport.SSL))
         {
-            SslContextFactory sslContextFactory = getSslContextFactory(port);
+            sslContextFactory = createSslContextFactory(port);
             ConnectionFactory sslConnectionFactory;
             if (port.getTransports().contains(Transport.TCP))
             {
@@ -523,6 +565,7 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem
                 }
                 catch (BindException e)
                 {
+                    _sslContextFactoryMap.remove(port);
                     InetSocketAddress addr = getHost() == null ? new InetSocketAddress(getPort())
                             : new InetSocketAddress(getHost(), getPort());
                     throw new PortBindFailureException(addr);
@@ -589,40 +632,16 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem
                     acceptors,
                     selectors));
         }
+        if (sslContextFactory != null)
+        {
+            _sslContextFactoryMap.put(port, sslContextFactory);
+        }
 
         return connector;
     }
 
-    private SslContextFactory getSslContextFactory(final HttpPort<?> port)
+    private SslContextFactory createSslContextFactory(final HttpPort<?> port)
     {
-        KeyStore keyStore = port.getKeyStore();
-        if (keyStore == null)
-        {
-            throw new IllegalConfigurationException(
-                    "Key store is not configured. Cannot start management on HTTPS port without keystore");
-        }
-
-        boolean needClientCert = port.getNeedClientAuth() || port.getWantClientAuth();
-        Collection<TrustStore> trustStores = port.getTrustStores();
-
-        if (needClientCert && trustStores.isEmpty())
-        {
-            throw new IllegalConfigurationException(String.format(
-                    "Client certificate authentication is enabled on HTTPS port '%s' but no trust store defined",
-                    this.getName()));
-        }
-
-        SSLContext sslContext = SSLUtil.createSslContext(keyStore, trustStores, port.getName());
-        SSLSessionContext serverSessionContext = sslContext.getServerSessionContext();
-        if (port.getTLSSessionCacheSize() > 0)
-        {
-            serverSessionContext.setSessionCacheSize(port.getTLSSessionCacheSize());
-        }
-        if (port.getTLSSessionTimeout() > 0)
-        {
-            serverSessionContext.setSessionTimeout(port.getTLSSessionTimeout());
-        }
-
         SslContextFactory factory = new SslContextFactory()
         {
             @Override
@@ -644,7 +663,7 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem
                                                   port.getTlsProtocolBlackList());
             }
         };
-        factory.setSslContext(sslContext);
+        factory.setSslContext(createSslContext(port));
         if (port.getNeedClientAuth())
         {
             factory.setNeedClientAuth(true);
@@ -656,6 +675,38 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem
         return factory;
     }
 
+    private SSLContext createSslContext(final HttpPort<?> port)
+    {
+        KeyStore keyStore = port.getKeyStore();
+        if (keyStore == null)
+        {
+            throw new IllegalConfigurationException(
+                    "Key store is not configured. Cannot start management on HTTPS port without keystore");
+        }
+
+        final boolean needClientCert = port.getNeedClientAuth() || port.getWantClientAuth();
+        final Collection<TrustStore> trustStores = port.getTrustStores();
+
+        if (needClientCert && trustStores.isEmpty())
+        {
+            throw new IllegalConfigurationException(String.format(
+                    "Client certificate authentication is enabled on HTTPS port '%s' but no trust store defined",
+                    this.getName()));
+        }
+
+        final SSLContext sslContext = SSLUtil.createSslContext(port.getKeyStore(), trustStores, port.getName());
+        final SSLSessionContext serverSessionContext = sslContext.getServerSessionContext();
+        if (port.getTLSSessionCacheSize() > 0)
+        {
+            serverSessionContext.setSessionCacheSize(port.getTLSSessionCacheSize());
+        }
+        if (port.getTLSSessionTimeout() > 0)
+        {
+            serverSessionContext.setSessionTimeout(port.getTLSSessionTimeout());
+        }
+        return sslContext;
+    }
+
     private void addRestServlet(final ServletContextHandler root)
     {
         final Map<String, ManagementControllerFactory> factories = ManagementControllerFactory.loadFactories();
@@ -934,6 +985,7 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem
                 Server server = _server;
                 if (server != null)
                 {
+                    _sslContextFactoryMap.remove(port);
                     final ServerConnector connector = _portConnectorMap.remove(port);
                     if (connector != null)
                     {
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Port.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Port.js
index 153c3f7..44c6675 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Port.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Port.js
@@ -72,6 +72,11 @@ define(["dojo/dom",
                         that.showEditDialog();
                     });
 
+                    that.updateTLSButton = registry.byNode(query(".updateTLSButton", contentPane.containerNode)[0]);
+                    that.updateTLSButton.on("click", function (evt) {
+                        that.updateTLS();
+                    });
+
                     that.portUpdater.update(function ()
                     {
                         updater.add(that.portUpdater);
@@ -116,6 +121,28 @@ define(["dojo/dom",
                 }, util.xhrErrorHandler);
         };
 
+        Port.prototype.updateTLS = function ()
+        {
+            if (confirm("Are you sure you want to update TLS?"))
+            {
+                this.updateTLSButton.set("disabled", true);
+                var that = this;
+                this.management.update({parent: this.modelObj, type: this.modelObj.type, name: "updateTLS"}, {})
+                    .then(function (data)
+                    {
+                        that.updateTLSButton.set("disabled", false);
+                        if (data)
+                        {
+                            alert("TLS was successfully updated.");
+                        }
+                        else
+                        {
+                            alert("TLS was not updated.");
+                        }
+                    });
+            }
+        };
+
         function PortUpdater(portTab)
         {
             var that = this;
@@ -197,6 +224,7 @@ define(["dojo/dom",
                 : "";
             this.protocolsValue.innerHTML = printArray("protocols", this.portData);
             this.transportsValue.innerHTML = printArray("transports", this.portData);
+            this.tabObject.updateTLSButton.set("disabled", !this.portData.tlsSupported);
             this.bindingAddressValue.innerHTML =
                 this.portData["bindingAddress"] ? entities.encode(String(this.portData["bindingAddress"])) : "";
             this.maxOpenConnectionsValue.innerHTML =
diff --git a/broker-plugins/management-http/src/main/java/resources/showPort.html b/broker-plugins/management-http/src/main/java/resources/showPort.html
index 883f3f9..6543080 100644
--- a/broker-plugins/management-http/src/main/java/resources/showPort.html
+++ b/broker-plugins/management-http/src/main/java/resources/showPort.html
@@ -113,6 +113,7 @@
         <div class="clear"></div>
     </div>
     <div class="dijitDialogPaneActionBar">
+        <button data-dojo-type="dijit.form.Button" class="updateTLSButton" type="button">Update TLS</button>
         <button data-dojo-type="dijit.form.Button" class="editPortButton" type="button">Edit</button>
         <button data-dojo-type="dijit.form.Button" class="deletePortButton" type="button">Delete</button>
     </div>
diff --git a/broker-plugins/websocket/src/main/java/org/apache/qpid/server/transport/websocket/WebSocketProvider.java b/broker-plugins/websocket/src/main/java/org/apache/qpid/server/transport/websocket/WebSocketProvider.java
index 8394ca8..2d4e494 100644
--- a/broker-plugins/websocket/src/main/java/org/apache/qpid/server/transport/websocket/WebSocketProvider.java
+++ b/broker-plugins/websocket/src/main/java/org/apache/qpid/server/transport/websocket/WebSocketProvider.java
@@ -65,6 +65,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.qpid.server.bytebuffer.QpidByteBuffer;
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
 import org.apache.qpid.server.model.Broker;
 import org.apache.qpid.server.model.Protocol;
 import org.apache.qpid.server.model.Transport;
@@ -87,7 +88,7 @@ class WebSocketProvider implements AcceptingTransport
     private static final String AMQP_WEBSOCKET_SUBPROTOCOL = "amqp";
 
     private final Transport _transport;
-    private final SSLContext _sslContext;
+    private final SslContextFactory _sslContextFactory;
     private final AmqpPort<?> _port;
     private final Broker<?> _broker;
     private final Set<Protocol> _supported;
@@ -108,7 +109,7 @@ class WebSocketProvider implements AcceptingTransport
                       final Protocol defaultSupportedProtocolReply)
     {
         _transport = transport;
-        _sslContext = sslContext;
+        _sslContextFactory = transport == Transport.WSS ? createSslContextFactory(port) : null;
         _port = port;
         _broker = ((Broker<?>) port.getParent());
         _supported = supported;
@@ -142,29 +143,7 @@ class WebSocketProvider implements AcceptingTransport
         }
         else if (_transport == Transport.WSS)
         {
-            SslContextFactory sslContextFactory = new SslContextFactory()
-                                        {
-                                            @Override
-                                            public void customize(final SSLEngine sslEngine)
-                                            {
-                                                super.customize(sslEngine);
-                                                SSLUtil.updateEnabledCipherSuites(sslEngine, _port.getTlsCipherSuiteWhiteList(), _port.getTlsCipherSuiteBlackList());
-                                                SSLUtil.updateEnabledTlsProtocols(sslEngine, _port.getTlsProtocolWhiteList(), _port.getTlsProtocolBlackList());
-
-                                                if(_port.getTlsCipherSuiteWhiteList() != null
-                                                   && !_port.getTlsCipherSuiteWhiteList().isEmpty())
-                                                {
-                                                    SSLParameters sslParameters = sslEngine.getSSLParameters();
-                                                    sslParameters.setUseCipherSuitesOrder(true);
-                                                    sslEngine.setSSLParameters(sslParameters);
-                                                }
-                                            }
-                                        };
-            sslContextFactory.setSslContext(_sslContext);
-
-            sslContextFactory.setNeedClientAuth(_port.getNeedClientAuth());
-            sslContextFactory.setWantClientAuth(_port.getWantClientAuth());
-            connector = new ServerConnector(_server, sslContextFactory, httpConnectionFactory);
+            connector = new ServerConnector(_server, _sslContextFactory, httpConnectionFactory);
             connector.addBean(new SslHandshakeListener()
             {
                 @Override
@@ -270,6 +249,36 @@ class WebSocketProvider implements AcceptingTransport
 
     }
 
+    private SslContextFactory createSslContextFactory(final AmqpPort<?> port)
+    {
+        SslContextFactory sslContextFactory = new SslContextFactory()
+        {
+            @Override
+            public void customize(final SSLEngine sslEngine)
+            {
+                super.customize(sslEngine);
+                SSLUtil.updateEnabledCipherSuites(sslEngine,
+                                                  port.getTlsCipherSuiteWhiteList(),
+                                                  port.getTlsCipherSuiteBlackList());
+                SSLUtil.updateEnabledTlsProtocols(sslEngine,
+                                                  port.getTlsProtocolWhiteList(),
+                                                  port.getTlsProtocolBlackList());
+
+                if (port.getTlsCipherSuiteWhiteList() != null
+                    && !port.getTlsCipherSuiteWhiteList().isEmpty())
+                {
+                    SSLParameters sslParameters = sslEngine.getSSLParameters();
+                    sslParameters.setUseCipherSuitesOrder(true);
+                    sslEngine.setSSLParameters(sslParameters);
+                }
+            }
+        };
+        sslContextFactory.setSslContext(port.getSSLContext());
+        sslContextFactory.setNeedClientAuth(port.getNeedClientAuth());
+        sslContextFactory.setWantClientAuth(port.getWantClientAuth());
+        return sslContextFactory;
+    }
+
     @Override
     public void close()
     {
@@ -295,6 +304,28 @@ class WebSocketProvider implements AcceptingTransport
                 ((ServerConnector) server.getConnectors()[0]).getLocalPort();
     }
 
+    @Override
+    public boolean updatesSSLContext()
+    {
+        if (_sslContextFactory != null)
+        {
+            try
+            {
+                _sslContextFactory.reload(f -> {
+                    f.setSslContext(_port.getSSLContext());
+                    f.setNeedClientAuth(_port.getNeedClientAuth());
+                    f.setWantClientAuth(_port.getWantClientAuth());
+                });
+                return true;
+            }
+            catch (Exception e)
+            {
+                throw new IllegalConfigurationException("Unexpected exception on reload of ssl context factory", e);
+            }
+        }
+        return false;
+    }
+
     private static class QBBTrackingThreadPool extends QueuedThreadPool
     {
         private final ThreadFactory _threadFactory = QpidByteBuffer.createQpidByteBufferTrackingThreadFactory(r -> QBBTrackingThreadPool.super.newThread(r));
diff --git a/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/endtoend/port/PortTest.java b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/endtoend/port/PortTest.java
new file mode 100644
index 0000000..320a73a
--- /dev/null
+++ b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/endtoend/port/PortTest.java
@@ -0,0 +1,400 @@
+package org.apache.qpid.tests.http.endtoend.port;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static javax.servlet.http.HttpServletResponse.SC_CREATED;
+import static javax.servlet.http.HttpServletResponse.SC_OK;
+import static org.apache.qpid.test.utils.TestSSLConstants.JAVA_KEYSTORE_TYPE;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeThat;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.NamingException;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.server.security.NonJavaKeyStore;
+import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager;
+import org.apache.qpid.server.transport.network.security.ssl.SSLUtil;
+import org.apache.qpid.server.util.DataUrlUtils;
+import org.apache.qpid.systests.ConnectionBuilder;
+import org.apache.qpid.tests.http.HttpTestBase;
+import org.apache.qpid.tests.http.HttpTestHelper;
+
+public class PortTest extends HttpTestBase
+{
+    private static final String PASS = "changeit";
+    private static final String QUEUE_NAME = "testQueue";
+    private static final TypeReference<Boolean> BOOLEAN = new TypeReference<Boolean>()
+    {
+    };
+    private String _portName;
+    private String _authenticationProvider;
+    private String _keyStoreName;
+    private Set<File> _storeFiles;
+    private File _storeFile;
+
+    @Before
+    public void setUp() throws Exception
+    {
+        assumeThat(SSLUtil.canGenerateCerts(), is(true));
+
+        _portName = getTestName();
+        _authenticationProvider = _portName + "AuthenticationProvider";
+        _keyStoreName = _portName + "KeyStore";
+        createAnonymousAuthenticationProvider();
+        final SSLUtil.KeyCertPair keyCertPair = createKeyStore(_keyStoreName);
+        final X509Certificate certificate = keyCertPair.getCertificate();
+
+        _storeFiles = new HashSet<>();
+        _storeFile = createTrustStore(certificate);
+
+        getBrokerAdmin().createQueue(QUEUE_NAME);
+    }
+
+
+    @After
+    public void tearDown()
+    {
+        _storeFiles.forEach(f -> assertTrue(f.delete()));
+    }
+
+    @Test
+    public void testSwapKeyStoreAndUpdateTlsOnAmqpPort() throws Exception
+    {
+        final int port = createPort(Transport.SSL);
+        final Connection connection = createConnection(port, _storeFile.getAbsolutePath());
+        try
+        {
+            final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            final MessageProducer producer = session.createProducer(session.createQueue(QUEUE_NAME));
+            producer.send(session.createTextMessage("A"));
+
+            final SSLUtil.KeyCertPair keyCertPair = createKeyStoreAndUpdatePortTLS();
+            final File storeFile = createTrustStore(keyCertPair.getCertificate());
+            final Connection connection2 = createConnection(port, storeFile.getAbsolutePath());
+            try
+            {
+                producer.send(session.createTextMessage("B"));
+
+                final Session session2 = connection2.createSession(false, Session.AUTO_ACKNOWLEDGE);
+                final MessageConsumer consumer = session2.createConsumer(session2.createQueue(QUEUE_NAME));
+                connection2.start();
+
+                assertMessage(consumer.receive(getReceiveTimeout()), "A");
+                assertMessage(consumer.receive(getReceiveTimeout()), "B");
+            }
+            finally
+            {
+                connection2.close();
+            }
+        }
+        finally
+        {
+            connection.close();
+        }
+    }
+
+    @Test
+    public void testUpdateKeyStoreAndUpdateTlsOnAmqpPort() throws Exception
+    {
+        final int port = createPort(Transport.SSL);
+        final Connection connection = createConnection(port, _storeFile.getAbsolutePath());
+        try
+        {
+            final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            final MessageProducer producer = session.createProducer(session.createQueue(QUEUE_NAME));
+            producer.send(session.createTextMessage("A"));
+
+            final SSLUtil.KeyCertPair keyCertPair = updateKeyStoreAndUpdatePortTLS();
+            final File storeFile = createTrustStore(keyCertPair.getCertificate());
+            final Connection connection2 = createConnection(port, storeFile.getAbsolutePath());
+            try
+            {
+                producer.send(session.createTextMessage("B"));
+
+                final Session session2 = connection2.createSession(false, Session.AUTO_ACKNOWLEDGE);
+                final MessageConsumer consumer = session2.createConsumer(session2.createQueue(QUEUE_NAME));
+                connection2.start();
+
+                assertMessage(consumer.receive(getReceiveTimeout()), "A");
+                assertMessage(consumer.receive(getReceiveTimeout()), "B");
+            }
+            finally
+            {
+                connection2.close();
+            }
+        }
+        finally
+        {
+            connection.close();
+        }
+    }
+
+    @Test
+    public void testSwapKeyStoreAndUpdateTlsOnWssPort() throws Exception
+    {
+        assumeThat(getProtocol(), is(equalTo(Protocol.AMQP_1_0)));
+        final int port = createPort(Transport.WSS);
+        final Connection connection = createConnectionBuilder(port, _storeFile.getAbsolutePath())
+                .setTransport("amqpws").build();
+        try
+        {
+            final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            final MessageProducer producer = session.createProducer(session.createQueue(QUEUE_NAME));
+            producer.send(session.createTextMessage("A"));
+
+            final SSLUtil.KeyCertPair keyCertPair = createKeyStoreAndUpdatePortTLS();
+            final File storeFile = createTrustStore(keyCertPair.getCertificate());
+            final Connection connection2 = createConnectionBuilder(port, storeFile.getAbsolutePath())
+                    .setTransport("amqpws").build();
+            try
+            {
+                producer.send(session.createTextMessage("B"));
+
+                final Session session2 = connection2.createSession(false, Session.AUTO_ACKNOWLEDGE);
+                final MessageConsumer consumer = session2.createConsumer(session2.createQueue(QUEUE_NAME));
+                connection2.start();
+
+                assertMessage(consumer.receive(getReceiveTimeout()), "A");
+                assertMessage(consumer.receive(getReceiveTimeout()), "B");
+            }
+            finally
+            {
+                connection2.close();
+            }
+        }
+        finally
+        {
+            connection.close();
+        }
+    }
+
+    @Test
+    public void testSwapKeyStoreAndUpdateTlsOnHttpPort() throws Exception
+    {
+        final int port = createHttpPort();
+
+        HttpTestHelper helper = new HttpTestHelper(getBrokerAdmin(), null, port);
+        helper.setTls(true);
+        helper.setKeyStore(_storeFile.getAbsolutePath(), PASS);
+
+        final Map<String, Object> attributes = getHelper().getJsonAsMap("port/" + _portName);
+        final Map<String, Object> ownAttributes = helper.getJsonAsMap("port/" + _portName);
+        assertEquals(attributes, ownAttributes);
+
+        final SSLUtil.KeyCertPair keyCertPair = createKeyStoreAndUpdatePortTLS();
+        final File storeFile = createTrustStore(keyCertPair.getCertificate());
+        helper.setKeyStore(storeFile.getAbsolutePath(), PASS);
+
+        final Map<String, Object> attributes2 = getHelper().getJsonAsMap("port/" + _portName);
+        final Map<String, Object> ownAttributes2 = helper.getJsonAsMap("port/" + _portName);
+        assertEquals(attributes2, ownAttributes2);
+    }
+
+    private void createAnonymousAuthenticationProvider() throws IOException
+    {
+        final Map<String, Object> data = Collections.singletonMap(ConfiguredObject.TYPE,
+                                                                  AnonymousAuthenticationManager.PROVIDER_TYPE);
+        getHelper().submitRequest("authenticationprovider/" + _authenticationProvider, "PUT", data, SC_CREATED);
+    }
+
+    private SSLUtil.KeyCertPair createKeyStore(final String keyStoreName) throws Exception
+    {
+        return submitKeyStoreAttributes(keyStoreName, SC_CREATED);
+    }
+
+    private SSLUtil.KeyCertPair submitKeyStoreAttributes(final String keyStoreName, final int status) throws Exception
+    {
+        final SSLUtil.KeyCertPair keyCertPair = generateSelfSignedCertificate();
+
+        final Map<String, Object> attributes = new HashMap<>();
+        attributes.put(NonJavaKeyStore.NAME, keyStoreName);
+        attributes.put(NonJavaKeyStore.PRIVATE_KEY_URL,
+                       DataUrlUtils.getDataUrlForBytes(toPEM(keyCertPair.getPrivateKey()).getBytes(UTF_8)));
+        attributes.put(NonJavaKeyStore.CERTIFICATE_URL,
+                       DataUrlUtils.getDataUrlForBytes(toPEM(keyCertPair.getCertificate()).getBytes(UTF_8)));
+        attributes.put(NonJavaKeyStore.TYPE, "NonJavaKeyStore");
+
+        getHelper().submitRequest("keystore/" + keyStoreName, "PUT", attributes, status);
+        return keyCertPair;
+    }
+
+    private ConnectionBuilder createConnectionBuilder(final int port, final String absolutePath)
+    {
+        return getConnectionBuilder().setPort(port)
+                                     .setTls(true)
+                                     .setVerifyHostName(false)
+                                     .setTrustStoreLocation(absolutePath)
+                                     .setTrustStorePassword(PASS);
+    }
+
+    private Connection createConnection(final int port, final String absolutePath)
+            throws NamingException, JMSException
+    {
+        return createConnectionBuilder(port, absolutePath).build();
+    }
+
+    private int createPort(final Transport transport) throws IOException
+    {
+        return createPort("AMQP",  transport);
+    }
+
+    private int createHttpPort() throws IOException
+    {
+        return createPort("HTTP",  Transport.SSL);
+    }
+
+    private int createPort(final String type, final Transport transport) throws IOException
+    {
+        final Map<String, Object> port = new HashMap<>();
+        port.put(Port.NAME, _portName);
+        port.put(Port.AUTHENTICATION_PROVIDER, _authenticationProvider);
+        port.put(Port.TYPE, type);
+        port.put(Port.PORT, 0);
+        port.put(Port.KEY_STORE, _keyStoreName);
+        port.put(Port.TRANSPORTS, Collections.singleton(transport));
+
+        getHelper().submitRequest("port/" + _portName, "PUT", port, SC_CREATED);
+
+        return getBoundPort();
+    }
+
+    private int getBoundPort() throws IOException
+    {
+        final Map<String, Object> attributes = getHelper().getJsonAsMap("port/" + _portName);
+        assertTrue(attributes.containsKey("boundPort"));
+        assertTrue(attributes.get("boundPort") instanceof Number);
+
+        return ((Number) attributes.get("boundPort")).intValue();
+    }
+
+    private File createTrustStore(final X509Certificate certificate)
+            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException
+    {
+        final java.security.KeyStore ks = java.security.KeyStore.getInstance(JAVA_KEYSTORE_TYPE);
+        ks.load(null);
+        ks.setCertificateEntry("certificate", certificate);
+        final File storeFile = File.createTempFile(getTestName(), ".pkcs12");
+        try (FileOutputStream fos = new FileOutputStream(storeFile))
+        {
+            ks.store(fos, PASS.toCharArray());
+        }
+        finally
+        {
+            _storeFiles.add(storeFile);
+        }
+        return storeFile;
+    }
+
+    private SSLUtil.KeyCertPair generateSelfSignedCertificate() throws Exception
+    {
+        return SSLUtil.generateSelfSignedCertificate("RSA",
+                                                     "SHA256WithRSA",
+                                                     2048,
+                                                     Instant.now()
+                                                            .minus(1, ChronoUnit.DAYS)
+                                                            .toEpochMilli(),
+                                                     Duration.of(365, ChronoUnit.DAYS)
+                                                             .getSeconds(),
+                                                     "CN=foo",
+                                                     Collections.emptySet(),
+                                                     Collections.emptySet());
+    }
+
+    private String toPEM(final Certificate pub) throws CertificateEncodingException
+    {
+        return toPEM(pub.getEncoded(), "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----");
+    }
+
+    private String toPEM(final PrivateKey key)
+    {
+        return toPEM(key.getEncoded(), "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----");
+    }
+
+    private String toPEM(final byte[] bytes, final String header, final String footer)
+    {
+        StringBuilder pem = new StringBuilder();
+        pem.append(header).append("\n");
+        String base64encoded = Base64.getEncoder().encodeToString(bytes);
+        while (base64encoded.length() > 76)
+        {
+            pem.append(base64encoded, 0, 76).append("\n");
+            base64encoded = base64encoded.substring(76);
+        }
+        pem.append(base64encoded).append("\n");
+        pem.append(footer).append("\n");
+        return pem.toString();
+    }
+
+    private void assertMessage(final Message messageA, final String a) throws JMSException
+    {
+        assertThat(messageA, is(notNullValue()));
+        assertThat(messageA, is(instanceOf(TextMessage.class)));
+        assertThat(((TextMessage) messageA).getText(), is(equalTo(a)));
+    }
+
+    private SSLUtil.KeyCertPair createKeyStoreAndUpdatePortTLS() throws Exception
+    {
+        final SSLUtil.KeyCertPair keyCertPair = createKeyStore(_keyStoreName + "_2");
+        final Map<String, Object> data = Collections.singletonMap(Port.KEY_STORE, _keyStoreName + "_2");
+        getHelper().submitRequest("port/" + _portName, "POST", data, SC_OK);
+        final boolean response = getHelper().postJson("port/" + _portName + "/updateTLS",
+                                                      Collections.emptyMap(),
+                                                      BOOLEAN,
+                                                      SC_OK);
+        assertTrue(response);
+
+        return keyCertPair;
+    }
+
+    private SSLUtil.KeyCertPair updateKeyStoreAndUpdatePortTLS() throws Exception
+    {
+        final SSLUtil.KeyCertPair keyCertPair = submitKeyStoreAttributes(_keyStoreName, SC_OK);
+        final boolean response = getHelper().postJson("port/" + _portName + "/updateTLS",
+                                                      Collections.emptyMap(),
+                                                      BOOLEAN,
+                                                      SC_OK);
+        assertTrue(response);
+
+        return keyCertPair;
+    }
+}
diff --git a/systests/qpid-systests-jms-core/src/main/java/org/apache/qpid/systests/ConnectionBuilder.java b/systests/qpid-systests-jms-core/src/main/java/org/apache/qpid/systests/ConnectionBuilder.java
index 4f113b4..fe64610 100644
--- a/systests/qpid-systests-jms-core/src/main/java/org/apache/qpid/systests/ConnectionBuilder.java
+++ b/systests/qpid-systests-jms-core/src/main/java/org/apache/qpid/systests/ConnectionBuilder.java
@@ -68,4 +68,6 @@ public interface ConnectionBuilder
     Connection build() throws NamingException, JMSException;
     ConnectionFactory buildConnectionFactory() throws NamingException;
     String buildConnectionURL();
+
+    ConnectionBuilder setTransport(String transport);
 }
diff --git a/systests/qpid-systests-jms-core/src/main/java/org/apache/qpid/systests/QpidJmsClient0xConnectionBuilder.java b/systests/qpid-systests-jms-core/src/main/java/org/apache/qpid/systests/QpidJmsClient0xConnectionBuilder.java
index 914cbe8..7935cb3 100644
--- a/systests/qpid-systests-jms-core/src/main/java/org/apache/qpid/systests/QpidJmsClient0xConnectionBuilder.java
+++ b/systests/qpid-systests-jms-core/src/main/java/org/apache/qpid/systests/QpidJmsClient0xConnectionBuilder.java
@@ -72,7 +72,7 @@ public class QpidJmsClient0xConnectionBuilder implements ConnectionBuilder
     public ConnectionBuilder setPort(final int port)
     {
         _port = port;
-        return this;
+        return setSslPort(port);
     }
 
     @Override
@@ -361,6 +361,12 @@ public class QpidJmsClient0xConnectionBuilder implements ConnectionBuilder
         return cUrlBuilder.toString();
     }
 
+    @Override
+    public ConnectionBuilder setTransport(final String transport)
+    {
+        throw new UnsupportedOperationException("Cannot modify transport");
+    }
+
     private String buildTransportQuery()
     {
         final StringBuilder builder = new StringBuilder();
diff --git a/systests/qpid-systests-jms-core/src/main/java/org/apache/qpid/systests/QpidJmsClientConnectionBuilder.java b/systests/qpid-systests-jms-core/src/main/java/org/apache/qpid/systests/QpidJmsClientConnectionBuilder.java
index 6da37ca..c47e81e 100644
--- a/systests/qpid-systests-jms-core/src/main/java/org/apache/qpid/systests/QpidJmsClientConnectionBuilder.java
+++ b/systests/qpid-systests-jms-core/src/main/java/org/apache/qpid/systests/QpidJmsClientConnectionBuilder.java
@@ -51,6 +51,7 @@ public class QpidJmsClientConnectionBuilder implements ConnectionBuilder
     private boolean _enableTls;
     private boolean _enableFailover;
     private final List<Integer> _failoverPorts = new ArrayList<>();
+    private String _transport = "amqp";
 
     QpidJmsClientConnectionBuilder()
     {
@@ -72,7 +73,7 @@ public class QpidJmsClientConnectionBuilder implements ConnectionBuilder
     public ConnectionBuilder setPort(final int port)
     {
         _port = port;
-        return this;
+        return setSslPort(port);
     }
 
     @Override
@@ -351,18 +352,25 @@ public class QpidJmsClientConnectionBuilder implements ConnectionBuilder
         }
         else if (!_enableTls)
         {
-            connectionUrlBuilder.append("amqp://").append(_host).append(":").append(_port);
+            connectionUrlBuilder.append(_transport).append("://").append(_host).append(":").append(_port);
 
             appendOptions(options, connectionUrlBuilder);
         }
         else
         {
-            connectionUrlBuilder.append("amqps://").append(_host).append(":").append(_sslPort);
+            connectionUrlBuilder.append(_transport).append("s").append("://").append(_host).append(":").append(_sslPort);
             appendOptions(options, connectionUrlBuilder);
         }
         return connectionUrlBuilder.toString();
     }
 
+    @Override
+    public ConnectionBuilder setTransport(final String transport)
+    {
+        _transport = transport;
+        return this;
+    }
+
     private void appendOptions(final Map<String, Object> actualOptions, final StringBuilder stem)
     {
         boolean first = true;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-broker-j] 02/02: QPID-8307:[Broker-J][Documentation] Document how to specify virtualhost initial configuration

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git

commit 6dc4f78e7fca09b6466103324f388715d5c43327
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Wed May 8 20:58:35 2019 +0100

    QPID-8307:[Broker-J][Documentation] Document how to specify virtualhost initial configuration
---
 .../docbkx/Java-Broker-Initial-Configuration.xml   | 36 +++++++++++++++++++---
 .../Java-Broker-Concepts-Virtualhost-Nodes.xml     |  5 +++
 2 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/doc/java-broker/src/docbkx/Java-Broker-Initial-Configuration.xml b/doc/java-broker/src/docbkx/Java-Broker-Initial-Configuration.xml
index bfd68f2..3a99393 100644
--- a/doc/java-broker/src/docbkx/Java-Broker-Initial-Configuration.xml
+++ b/doc/java-broker/src/docbkx/Java-Broker-Initial-Configuration.xml
@@ -363,11 +363,7 @@ $ ./qpid-server -prop "qpid.amqp_port=10000" -prop "qpid.http_port=10001"
                         </para>
                     </listitem>
                     <listitem>
-                        <para> Virtualhost Node called default. On initial startup, it
-                            virtualHostInitialConfiguration will cause a virtualhost to be created
-                            with the same name. The configuration will be stored in a
-                                <emphasis>JSON</emphasis> configuration store, the message data will
-                            be stored in a <emphasis>DERBY</emphasis> message store.</para>
+                        <para> Virtualhost Node called <emphasis>default</emphasis>.</para>
                     </listitem>
                     <listitem>
                         <para>One management plugin: "httpManagement" of type "MANAGEMENT-HTTP".</para>
@@ -380,4 +376,34 @@ $ ./qpid-server -prop "qpid.amqp_port=10000" -prop "qpid.http_port=10001"
         </example>
     </section>
 
+    <section xml:id="Java-Broker-Virtual-Host-Initial-Configuration">
+        <title>Virtualhost Initial Configuration</title>
+        <para>
+            <emphasis>Virtualhost</emphasis> initial configuration can be specified in <emphasis>Virtualhost node</emphasis>
+            attribute <emphasis>virtualHostInitialConfiguration</emphasis>. On first startup,
+            the <emphasis>virtualhost</emphasis> is created based on provided initial configuration.
+            You can define there manageable <emphasis>Virtualhost</emphasis> attributes and children like exchanges, queues, etc.
+        </para>
+        <para>
+            The attribute <varname>virtualHostInitialConfiguration</varname> can have a value of <emphasis>URL</emphasis>
+            to an external resource where <emphasis>virtualhost</emphasis> initial configuration is provided in json format, or,
+            it can hold a string value with initial configuration in stringified json format. If required, you can
+            specify initial configuration as context variable which can be resolved as <emphasis>URL</emphasis>
+            to external resource or stringified json.
+        </para>
+        <example>
+        <title>Example of virtual host initial configuration provided as stringified JSON</title>
+        <programlisting>
+            ...
+            "virtualhostnodes" : [ {
+            "name" : "default",
+            "type" : "JSON",
+            "defaultVirtualHostNode" : "true",
+            "virtualHostInitialConfiguration" : "{\"type\":\"BDB\",\"nodeAutoCreationPolicies\":[{\"patterns\":\".*\",\"createdOnPublish\":\"true\",\"createdOnConsume\":\"true\",\"nodeType\":\"queue\"}]}"
+            } ]
+            ...</programlisting>
+        </example>
+        <para>After creation of <emphasis>virtualhost</emphasis> the value of
+            <varname>virtualHostInitialConfiguration</varname> is set to an empty string.</para>
+    </section>
 </chapter>
diff --git a/doc/java-broker/src/docbkx/concepts/Java-Broker-Concepts-Virtualhost-Nodes.xml b/doc/java-broker/src/docbkx/concepts/Java-Broker-Concepts-Virtualhost-Nodes.xml
index b4b9e41..ee7e8f0 100644
--- a/doc/java-broker/src/docbkx/concepts/Java-Broker-Concepts-Virtualhost-Nodes.xml
+++ b/doc/java-broker/src/docbkx/concepts/Java-Broker-Concepts-Virtualhost-Nodes.xml
@@ -31,4 +31,9 @@
     the group. The virtualhost nodes together elect a master. When the high availability feature is
     in use, the virtualhost node has <link linkend="Java-Broker-Concepts-RemoteReplicationNodes">remote replications nodes</link>. There is a remote replication node corresponding to each
     remote virtualhost node that form part of the group.</para>
+  <para>
+    <emphasis>Virtualhost node</emphasis> also provides an initial configuration for its <emphasis>virtualhost</emphasis>.
+    How to specify initial configuration for <emphasis>virtual host</emphasis> is described at
+    <xref linkend="Java-Broker-Virtual-Host-Initial-Configuration"/>.
+  </para>
 </section>


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org