You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by cl...@apache.org on 2016/10/24 13:42:43 UTC
[2/5] activemq-artemis git commit: ARTEMIS-814: Add support for
outgoing AMQP connections
ARTEMIS-814: Add support for outgoing AMQP connections
Project: http://git-wip-us.apache.org/repos/asf/activemq-artemis/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-artemis/commit/e65fd5d6
Tree: http://git-wip-us.apache.org/repos/asf/activemq-artemis/tree/e65fd5d6
Diff: http://git-wip-us.apache.org/repos/asf/activemq-artemis/diff/e65fd5d6
Branch: refs/heads/master
Commit: e65fd5d6748060ed8b54e05ef5b915964a0522b2
Parents: 6e5b917
Author: Ulf Lilleengen <lu...@redhat.com>
Authored: Fri Oct 21 15:24:16 2016 +0200
Committer: Clebert Suconic <cl...@apache.org>
Committed: Mon Oct 24 09:42:22 2016 -0400
----------------------------------------------------------------------
...ProtonClientConnectionLifeCycleListener.java | 107 +++++++++++++++++
.../broker/ProtonClientProtocolManager.java | 117 +++++++++++++++++++
.../amqp/proton/AMQPConnectionContext.java | 4 +
.../amqp/proton/handler/ProtonHandler.java | 7 ++
.../tests/integration/amqp/ProtonTest.java | 55 +++++++++
.../tests/integration/amqp/ProtonTestBase.java | 19 +--
6 files changed, 302 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/e65fd5d6/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ProtonClientConnectionLifeCycleListener.java
----------------------------------------------------------------------
diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ProtonClientConnectionLifeCycleListener.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ProtonClientConnectionLifeCycleListener.java
new file mode 100644
index 0000000..cf43444
--- /dev/null
+++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ProtonClientConnectionLifeCycleListener.java
@@ -0,0 +1,107 @@
+/*
+ * 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.activemq.artemis.protocol.amqp.broker;
+
+import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
+import org.apache.activemq.artemis.api.core.ActiveMQException;
+import org.apache.activemq.artemis.core.server.ActiveMQComponent;
+import org.apache.activemq.artemis.core.server.ActiveMQServer;
+import org.apache.activemq.artemis.protocol.amqp.proton.AMQPConnectionContext;
+import org.apache.activemq.artemis.protocol.amqp.proton.AMQPConstants;
+import org.apache.activemq.artemis.spi.core.protocol.ConnectionEntry;
+import org.apache.activemq.artemis.spi.core.remoting.BaseConnectionLifeCycleListener;
+import org.apache.activemq.artemis.spi.core.remoting.BufferHandler;
+import org.apache.activemq.artemis.spi.core.remoting.Connection;
+import org.jboss.logging.Logger;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+
+/**
+ * Manages the lifecycle of a proton client connection.
+ */
+public class ProtonClientConnectionLifeCycleListener implements BaseConnectionLifeCycleListener<ProtonProtocolManager>, BufferHandler {
+ private final Map<Object, ConnectionEntry> connectionMap = new ConcurrentHashMap<>();
+ private final ActiveMQServer server;
+ private final int ttl;
+ private static final Logger log = Logger.getLogger(ProtonClientConnectionLifeCycleListener.class);
+
+ public ProtonClientConnectionLifeCycleListener(ActiveMQServer server, int ttl) {
+ this.server = server;
+ this.ttl = ttl;
+ }
+
+ @Override
+ public void connectionCreated(ActiveMQComponent component, Connection connection, ProtonProtocolManager protocolManager) {
+ AMQPConnectionCallback connectionCallback = new AMQPConnectionCallback(protocolManager, connection, server.getExecutorFactory().getExecutor(), server);
+
+ String id = server.getConfiguration().getName();
+ AMQPConnectionContext amqpConnection = new AMQPConnectionContext(connectionCallback, id, ttl, protocolManager.getMaxFrameSize(), AMQPConstants.Connection.DEFAULT_CHANNEL_MAX, server.getExecutorFactory().getExecutor(), server.getScheduledPool());
+ Executor executor = server.getExecutorFactory().getExecutor();
+ amqpConnection.open();
+
+ ActiveMQProtonRemotingConnection delegate = new ActiveMQProtonRemotingConnection(protocolManager, amqpConnection, connection, executor);
+
+ connectionCallback.setProtonConnectionDelegate(delegate);
+
+ ConnectionEntry connectionEntry = new ConnectionEntry(delegate, executor, System.currentTimeMillis(), ttl);
+ connectionMap.put(connection.getID(), connectionEntry);
+ log.info("Connection " + connection.getRemoteAddress() + " created");
+ }
+
+ @Override
+ public void connectionDestroyed(Object connectionID) {
+ ConnectionEntry connection = connectionMap.remove(connectionID);
+ if (connection != null) {
+ log.info("Connection " + connection.connection.getRemoteAddress() + " destroyed");
+ connection.connection.disconnect(false);
+ }
+ }
+
+ @Override
+ public void connectionException(Object connectionID, ActiveMQException me) {
+ ConnectionEntry connection = connectionMap.get(connectionID);
+ if (connection != null) {
+ log.info("Connection " + connection.connection.getRemoteAddress() + " exception: " + me.getMessage());
+ connection.connection.fail(me);
+ }
+ }
+
+ @Override
+ public void connectionReadyForWrites(Object connectionID, boolean ready) {
+ ConnectionEntry connection = connectionMap.get(connectionID);
+ if (connection != null) {
+ log.info("Connection " + connection.connection.getRemoteAddress() + " ready");
+ connection.connection.getTransportConnection().fireReady(true);
+ }
+ }
+
+ public void stop() {
+ for (ConnectionEntry entry : connectionMap.values()) {
+ entry.connection.disconnect(false);
+ }
+ }
+
+ @Override
+ public void bufferReceived(Object connectionID, ActiveMQBuffer buffer) {
+ ConnectionEntry entry = connectionMap.get(connectionID);
+ if (entry != null) {
+ entry.connection.bufferReceived(connectionID, buffer);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/e65fd5d6/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ProtonClientProtocolManager.java
----------------------------------------------------------------------
diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ProtonClientProtocolManager.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ProtonClientProtocolManager.java
new file mode 100644
index 0000000..eca02d7
--- /dev/null
+++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ProtonClientProtocolManager.java
@@ -0,0 +1,117 @@
+/*
+ * 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.activemq.artemis.protocol.amqp.broker;
+
+import io.netty.channel.ChannelPipeline;
+import org.apache.activemq.artemis.api.core.ActiveMQException;
+import org.apache.activemq.artemis.api.core.Interceptor;
+import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
+import org.apache.activemq.artemis.core.server.ActiveMQServer;
+import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
+import org.apache.activemq.artemis.spi.core.remoting.ClientProtocolManager;
+import org.apache.activemq.artemis.spi.core.remoting.Connection;
+import org.apache.activemq.artemis.spi.core.remoting.SessionContext;
+import org.apache.activemq.artemis.spi.core.remoting.TopologyResponseHandler;
+
+import java.util.List;
+import java.util.concurrent.locks.Lock;
+
+/**
+ * Handles proton protocol management for clients, mapping the {@link ProtonProtocolManager} to the {@link org.apache.activemq.artemis.spi.core.remoting.ClientProtocolManager} API.
+ *
+ * TODO: Find a common base for ProtocolManager and ClientProtocolManager.
+ */
+public class ProtonClientProtocolManager extends ProtonProtocolManager implements ClientProtocolManager {
+
+ public ProtonClientProtocolManager(ProtonProtocolManagerFactory factory, ActiveMQServer server) {
+ super(factory, server);
+ }
+
+ @Override
+ public void stop() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public RemotingConnection connect(Connection transportConnection, long callTimeout, long callFailoverTimeout, List<Interceptor> incomingInterceptors, List<Interceptor> outgoingInterceptors, TopologyResponseHandler topologyResponseHandler) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public RemotingConnection getCurrentConnection() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Lock lockSessionCreation() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean waitOnLatch(long milliseconds) throws InterruptedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isAlive() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addChannelHandlers(ChannelPipeline pipeline) {
+ }
+
+ @Override
+ public void sendSubscribeTopology(boolean isServer) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void ping(long connectionTTL) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SessionContext createSessionContext(String name, String username, String password, boolean xa, boolean autoCommitSends, boolean autoCommitAcks, boolean preAcknowledge, int minLargeMessageSize, int confirmationWindowSize) throws ActiveMQException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean cleanupBeforeFailover(ActiveMQException cause) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean checkForFailover(String liveNodeID) throws ActiveMQException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setSessionFactory(ClientSessionFactory factory) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ClientSessionFactory getSessionFactory() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getName() {
+ throw new UnsupportedOperationException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/e65fd5d6/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/AMQPConnectionContext.java
----------------------------------------------------------------------
diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/AMQPConnectionContext.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/AMQPConnectionContext.java
index 65ed836..8957d99 100644
--- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/AMQPConnectionContext.java
+++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/AMQPConnectionContext.java
@@ -205,6 +205,10 @@ public class AMQPConnectionContext extends ProtonInitializable {
return ExtCapability.getCapabilities();
}
+ public void open() {
+ handler.open(containerId);
+ }
+
// This listener will perform a bunch of things here
class LocalListener implements EventHandler {
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/e65fd5d6/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/handler/ProtonHandler.java
----------------------------------------------------------------------
diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/handler/ProtonHandler.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/handler/ProtonHandler.java
index 3c088d5..b4ddda0 100644
--- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/handler/ProtonHandler.java
+++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/handler/ProtonHandler.java
@@ -357,4 +357,11 @@ public class ProtonHandler extends ProtonInitializable {
}
}
+
+ public void open(String containerId) {
+ this.transport.open();
+ this.connection.setContainer(containerId);
+ this.connection.open();
+ flush();
+ }
}
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/e65fd5d6/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/ProtonTest.java
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/ProtonTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/ProtonTest.java
index 15271f6..c1d1b71 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/ProtonTest.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/ProtonTest.java
@@ -29,6 +29,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
@@ -62,9 +63,15 @@ import javax.jms.TopicSubscriber;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.core.postoffice.Bindings;
import org.apache.activemq.artemis.core.remoting.CloseListener;
+import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnector;
+import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
+import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.Queue;
import org.apache.activemq.artemis.core.settings.impl.AddressFullMessagePolicy;
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
+import org.apache.activemq.artemis.protocol.amqp.broker.ProtonClientConnectionLifeCycleListener;
+import org.apache.activemq.artemis.protocol.amqp.broker.ProtonClientProtocolManager;
+import org.apache.activemq.artemis.protocol.amqp.broker.ProtonProtocolManagerFactory;
import org.apache.activemq.artemis.protocol.amqp.proton.AmqpSupport;
import org.apache.activemq.artemis.protocol.amqp.proton.ProtonServerReceiverContext;
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
@@ -949,6 +956,54 @@ public class ProtonTest extends ProtonTestBase {
}
+ @Test
+ public void testOutboundConnection() throws Throwable {
+ final ActiveMQServer remote = createAMQPServer(5673);
+ remote.start();
+ try {
+ Wait.waitFor(new Wait.Condition() {
+ @Override
+ public boolean isSatisified() throws Exception {
+ return remote.isActive();
+ }
+ });
+ } catch (Exception e) {
+ remote.stop();
+ throw e;
+ }
+
+ final Map<String, Object> config = new LinkedHashMap<>();
+ config.put(TransportConstants.HOST_PROP_NAME, "localhost");
+ config.put(TransportConstants.PORT_PROP_NAME, "5673");
+ ProtonClientConnectionLifeCycleListener lifeCycleListener = new ProtonClientConnectionLifeCycleListener(server, 5000);
+ ProtonClientProtocolManager protocolManager = new ProtonClientProtocolManager(new ProtonProtocolManagerFactory(), server);
+ NettyConnector connector = new NettyConnector(config, lifeCycleListener, lifeCycleListener, server.getExecutorFactory().getExecutor(), server.getExecutorFactory().getExecutor(), server.getScheduledPool(), protocolManager);
+ connector.start();
+ connector.createConnection();
+
+ try {
+ Wait.waitFor(new Wait.Condition() {
+ @Override
+ public boolean isSatisified() throws Exception {
+ return remote.getConnectionCount() > 0;
+ }
+ });
+ assertEquals(1, remote.getConnectionCount());
+
+ lifeCycleListener.stop();
+ Wait.waitFor(new Wait.Condition() {
+ @Override
+ public boolean isSatisified() throws Exception {
+ return remote.getConnectionCount() == 0;
+ }
+ });
+ assertEquals(0, remote.getConnectionCount());
+ } finally {
+ lifeCycleListener.stop();
+ remote.stop();
+ }
+ }
+
/*
// Uncomment testLoopBrowser to validate the hunging on the test
@Test
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/e65fd5d6/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/ProtonTestBase.java
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/ProtonTestBase.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/ProtonTestBase.java
index 9dacd66..a57e2ea 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/ProtonTestBase.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/ProtonTestBase.java
@@ -16,6 +16,7 @@
*/
package org.apache.activemq.artemis.tests.integration.amqp;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -42,23 +43,27 @@ public class ProtonTestBase extends ActiveMQTestBase {
public void setUp() throws Exception {
super.setUp();
- server = this.createServer(true, true);
+ server = this.createAMQPServer(5672);
+ server.start();
+ }
+
+ protected ActiveMQServer createAMQPServer(int port) throws Exception {
+ final ActiveMQServer amqpServer = this.createServer(true, true);
HashMap<String, Object> params = new HashMap<>();
- params.put(TransportConstants.PORT_PROP_NAME, "5672");
+ params.put(TransportConstants.PORT_PROP_NAME, String.valueOf(port));
params.put(TransportConstants.PROTOCOLS_PROP_NAME, "AMQP");
HashMap<String, Object> amqpParams = new HashMap<>();
configureAmqp(amqpParams);
TransportConfiguration transportConfiguration = new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params, "amqp-acceptor", amqpParams);
- server.getConfiguration().getAcceptorConfigurations().add(transportConfiguration);
- server.getConfiguration().setName(brokerName);
+ amqpServer.getConfiguration().setAcceptorConfigurations(Collections.singleton(transportConfiguration));
+ amqpServer.getConfiguration().setName(brokerName);
// Default Page
AddressSettings addressSettings = new AddressSettings();
addressSettings.setAddressFullMessagePolicy(AddressFullMessagePolicy.PAGE);
- server.getConfiguration().getAddressesSettings().put("#", addressSettings);
-
- server.start();
+ amqpServer.getConfiguration().getAddressesSettings().put("#", addressSettings);
+ return amqpServer;
}
protected void configureAmqp(Map<String, Object> params) {