From ae8550d569efca7f9efdda7d13a81b6f14cc0f02 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 23 Jul 2018 15:57:33 -0400 Subject: [PATCH] AMQP-812: Deprecate RabbitManagementTemplate (#779) * AMQP-812: Deprecate RabbitManagementTemplate JIRA: https://jira.spring.io/browse/AMQP-812 * Fix `RabbitRestApiTests` --- build.gradle | 2 +- .../amqp/core/AmqpManagementOperations.java | 4 +- .../rabbit/core/RabbitManagementTemplate.java | 7 ++- .../EnableRabbitIntegrationTests.java | 7 ++- .../core/RabbitAdminIntegrationTests.java | 24 +++---- ...lateTests.java => RabbitRestApiTests.java} | 63 ++++++++++++------- src/reference/asciidoc/amqp.adoc | 60 ++---------------- src/reference/asciidoc/appendix.adoc | 5 +- src/reference/asciidoc/whats-new.adoc | 12 ++-- 9 files changed, 80 insertions(+), 104 deletions(-) rename spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/{RabbitManagementTemplateTests.java => RabbitRestApiTests.java} (74%) diff --git a/build.gradle b/build.gradle index a29acdcc..348454ce 100644 --- a/build.gradle +++ b/build.gradle @@ -254,7 +254,7 @@ project('spring-rabbit') { compile project(":spring-amqp") compile "com.rabbitmq:amqp-client:$rabbitmqVersion" - compile "com.rabbitmq:http-client:$rabbitmqHttpClientVersion" + compile ("com.rabbitmq:http-client:$rabbitmqHttpClientVersion", optional) compile ("org.springframework:spring-aop:$springVersion", optional) compile "org.springframework:spring-context:$springVersion" diff --git a/spring-amqp/src/main/java/org/springframework/amqp/core/AmqpManagementOperations.java b/spring-amqp/src/main/java/org/springframework/amqp/core/AmqpManagementOperations.java index 1fc72d85..0d0d2c15 100644 --- a/spring-amqp/src/main/java/org/springframework/amqp/core/AmqpManagementOperations.java +++ b/spring-amqp/src/main/java/org/springframework/amqp/core/AmqpManagementOperations.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2016 the original author or authors. + * Copyright 2015-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,9 @@ import java.util.List; * @author Gary Russell * @since 1.5 * + * @deprecated since 2.1 in favor of direct usage of target REST API client. */ +@Deprecated public interface AmqpManagementOperations { /** diff --git a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitManagementTemplate.java b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitManagementTemplate.java index e37f8b0c..db3d5cad 100644 --- a/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitManagementTemplate.java +++ b/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/core/RabbitManagementTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2017 the original author or authors. + * Copyright 2015-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,6 @@ import java.util.stream.Collectors; import org.springframework.amqp.AmqpException; import org.springframework.amqp.core.AbstractExchange; -import org.springframework.amqp.core.AmqpManagementOperations; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.Binding.DestinationType; import org.springframework.amqp.core.DirectExchange; @@ -48,8 +47,10 @@ import com.rabbitmq.http.client.domain.QueueInfo; * * @since 1.5 * + * @deprecated since 2.1 in favor of direct {@link Client} usage. */ -public class RabbitManagementTemplate implements AmqpManagementOperations { +@Deprecated +public class RabbitManagementTemplate implements org.springframework.amqp.core.AmqpManagementOperations { private static final String DEFAULT_VHOST = "/"; diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/EnableRabbitIntegrationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/EnableRabbitIntegrationTests.java index 20234ac2..efc92aaf 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/EnableRabbitIntegrationTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/annotation/EnableRabbitIntegrationTests.java @@ -77,7 +77,6 @@ import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.connection.ConnectionNameStrategy; import org.springframework.amqp.rabbit.connection.SimplePropertyValueConnectionNameStrategy; import org.springframework.amqp.rabbit.core.RabbitAdmin; -import org.springframework.amqp.rabbit.core.RabbitManagementTemplate; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.junit.BrokerRunning; import org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler; @@ -140,6 +139,8 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.ErrorHandler; import com.rabbitmq.client.Channel; +import com.rabbitmq.http.client.Client; +import com.rabbitmq.http.client.domain.QueueInfo; /** * @@ -718,8 +719,8 @@ public class EnableRabbitIntegrationTests { this.rabbitTemplate.convertAndSend("amqp656", "foo"); assertEquals("foo", this.rabbitTemplate.receiveAndConvert("amqp656dlq", 10000)); try { - RabbitManagementTemplate rmt = new RabbitManagementTemplate(); - org.springframework.amqp.core.Queue amqp656 = rmt.getQueue("amqp656"); + Client rabbitRestClient = new Client("http://localhost:15672/api/", "guest", "guest"); + QueueInfo amqp656 = rabbitRestClient.getQueue("/", "amqp656"); if (amqp656 != null) { assertEquals("", amqp656.getArguments().get("test-empty")); assertEquals("undefined", amqp656.getArguments().get("test-null")); diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitAdminIntegrationTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitAdminIntegrationTests.java index c68b781a..c086f393 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitAdminIntegrationTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitAdminIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ package org.springframework.amqp.rabbit.core; import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.instanceOf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -41,6 +40,7 @@ import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.Binding.DestinationType; import org.springframework.amqp.core.DirectExchange; import org.springframework.amqp.core.Exchange; +import org.springframework.amqp.core.ExchangeTypes; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageBuilder; import org.springframework.amqp.core.MessageProperties; @@ -56,6 +56,8 @@ import com.rabbitmq.client.AMQP.Queue.DeclareOk; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.http.client.Client; +import com.rabbitmq.http.client.domain.ExchangeInfo; /** * @author Dave Syer @@ -260,8 +262,8 @@ public class RabbitAdminIntegrationTests { exchange.setInternal(true); rabbitAdmin.declareExchange(exchange); - Exchange exchange2 = getExchange(exchangeName); - assertThat(exchange2, instanceOf(DirectExchange.class)); + ExchangeInfo exchange2 = getExchange(exchangeName); + assertEquals(ExchangeTypes.DIRECT, exchange2.getType()); assertTrue(exchange2.isInternal()); boolean result = rabbitAdmin.deleteExchange(exchangeName); @@ -416,22 +418,22 @@ public class RabbitAdminIntegrationTests { assertEquals(Integer.valueOf(1000), received.getMessageProperties().getReceivedDelay()); assertThat(System.currentTimeMillis() - t1, greaterThan(950L)); - Exchange exchange2 = getExchange(exchangeName); + ExchangeInfo exchange2 = getExchange(exchangeName); assertNotNull(exchange2); - assertThat(exchange2, instanceOf(DirectExchange.class)); - assertTrue(exchange2.isDelayed()); + assertEquals(ExchangeTypes.DIRECT, exchange2.getArguments().get("x-delayed-type")); + assertEquals("x-delayed-message", exchange2.getType()); this.rabbitAdmin.deleteQueue(queue.getName()); this.rabbitAdmin.deleteExchange(exchangeName); } - private Exchange getExchange(String exchangeName) throws InterruptedException { - RabbitManagementTemplate rmt = new RabbitManagementTemplate(); + private ExchangeInfo getExchange(String exchangeName) throws Exception { + Client rabbitRestClient = new Client("http://localhost:15672/api/", "guest", "guest"); int n = 0; - Exchange exchange = rmt.getExchange(exchangeName); + ExchangeInfo exchange = rabbitRestClient.getExchange("/", exchangeName); while (n++ < 100 && exchange == null) { Thread.sleep(100); - exchange = rmt.getExchange(exchangeName); + exchange = rabbitRestClient.getExchange("/", exchangeName); } return exchange; } diff --git a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitManagementTemplateTests.java b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitRestApiTests.java similarity index 74% rename from spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitManagementTemplateTests.java rename to spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitRestApiTests.java index dfa15a03..b52ac138 100644 --- a/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitManagementTemplateTests.java +++ b/spring-rabbit/src/test/java/org/springframework/amqp/rabbit/core/RabbitRestApiTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2017 the original author or authors. + * Copyright 2015-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.util.Collections; import java.util.List; import java.util.Map; @@ -45,6 +47,9 @@ import org.springframework.amqp.rabbit.junit.BrokerRunning; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.http.client.Client; +import com.rabbitmq.http.client.domain.BindingInfo; +import com.rabbitmq.http.client.domain.ExchangeInfo; import com.rabbitmq.http.client.domain.QueueInfo; /** @@ -54,15 +59,20 @@ import com.rabbitmq.http.client.domain.QueueInfo; * @since 1.5 * */ -public class RabbitManagementTemplateTests { +public class RabbitRestApiTests { private final CachingConnectionFactory connectionFactory = new CachingConnectionFactory("localhost"); - private final RabbitManagementTemplate template = new RabbitManagementTemplate(); + private final Client rabbitRestClient; + @ClassRule public static BrokerRunning brokerAndManagementRunning = BrokerRunning.isBrokerAndManagementRunning(); + public RabbitRestApiTests() throws MalformedURLException, URISyntaxException { + this.rabbitRestClient = new Client("http://localhost:15672/api/", "guest", "guest"); + } + @After public void tearDown() { connectionFactory.destroy(); @@ -70,37 +80,37 @@ public class RabbitManagementTemplateTests { @Test public void testExchanges() { - List list = this.template.getExchanges(); + List list = this.rabbitRestClient.getExchanges(); assertTrue(list.size() > 0); } @Test public void testExchangesVhost() { - List list = this.template.getExchanges("/"); + List list = this.rabbitRestClient.getExchanges("/"); assertTrue(list.size() > 0); } @Test public void testBindings() { - List list = this.template.getBindings(); + List list = this.rabbitRestClient.getBindings(); assertTrue(list.size() > 0); } @Test public void testBindingsVhost() { - List list = this.template.getBindings("/"); + List list = this.rabbitRestClient.getBindings("/"); assertTrue(list.size() > 0); } @Test public void testQueues() { - List list = this.template.getQueues(); + List list = this.rabbitRestClient.getQueues(); assertTrue(list.size() > 0); } @Test public void testQueuesVhost() { - List list = this.template.getQueues("/"); + List list = this.rabbitRestClient.getQueues("/"); assertTrue(list.size() > 0); } @@ -125,12 +135,12 @@ public class RabbitManagementTemplateTests { .with("bar"); admin.declareBinding(binding2); - List bindings = this.template.getBindingsForExchange("/", exchange1.getName()); + List bindings = this.rabbitRestClient.getBindingsBySource("/", exchange1.getName()); assertEquals(2, bindings.size()); - assertEquals(exchange1.getName(), bindings.get(0).getExchange()); + assertEquals(exchange1.getName(), bindings.get(0).getSource()); assertThat("foo", anyOf(equalTo(bindings.get(0).getRoutingKey()), equalTo(bindings.get(1).getRoutingKey()))); - Binding qout = null; - Binding eout = null; + BindingInfo qout = null; + BindingInfo eout = null; if (bindings.get(0).getRoutingKey().equals("foo")) { qout = bindings.get(0); eout = bindings.get(1); @@ -139,12 +149,12 @@ public class RabbitManagementTemplateTests { eout = bindings.get(0); qout = bindings.get(1); } - assertEquals(Binding.DestinationType.QUEUE, qout.getDestinationType()); + assertEquals("queue", qout.getDestinationType()); assertEquals(queue.getName(), qout.getDestination()); assertNotNull(qout.getArguments()); assertEquals("", qout.getArguments().get("alternate-exchange")); - assertEquals(Binding.DestinationType.EXCHANGE, eout.getDestinationType()); + assertEquals("exchange", eout.getDestinationType()); assertEquals(exchange2.getName(), eout.getDestination()); admin.deleteExchange(exchange1.getName()); @@ -157,7 +167,7 @@ public class RabbitManagementTemplateTests { Map args = Collections.singletonMap("alternate-exchange", ""); Exchange exchange = new DirectExchange(UUID.randomUUID().toString(), true, true, args); admin.declareExchange(exchange); - Exchange exchangeOut = this.template.getExchange("/", exchange.getName()); + ExchangeInfo exchangeOut = this.rabbitRestClient.getExchange("/", exchange.getName()); assertTrue(exchangeOut.isDurable()); assertTrue(exchangeOut.isAutoDelete()); assertEquals(exchange.getName(), exchangeOut.getName()); @@ -180,13 +190,13 @@ public class RabbitManagementTemplateTests { admin.declareQueue(queue2); Channel channel = this.connectionFactory.createConnection().createChannel(false); String consumer = channel.basicConsume(queue1.getName(), false, "", false, true, null, new DefaultConsumer(channel)); - QueueInfo qi = this.template.getClient().getQueue("/", queue1.getName()); + QueueInfo qi = this.rabbitRestClient.getQueue("/", queue1.getName()); int n = 0; while (n++ < 100 && (qi.getExclusiveConsumerTag() == null || qi.getExclusiveConsumerTag().equals(""))) { Thread.sleep(100); - qi = this.template.getClient().getQueue("/", queue1.getName()); + qi = this.rabbitRestClient.getQueue("/", queue1.getName()); } - Queue queueOut = this.template.getQueue("/", queue1.getName()); + QueueInfo queueOut = this.rabbitRestClient.getQueue("/", queue1.getName()); assertFalse(queueOut.isDurable()); assertFalse(queueOut.isExclusive()); assertTrue(queueOut.isAutoDelete()); @@ -196,7 +206,7 @@ public class RabbitManagementTemplateTests { channel.basicCancel(consumer); channel.close(); - queueOut = this.template.getQueue("/", queue2.getName()); + queueOut = this.rabbitRestClient.getQueue("/", queue2.getName()); assertTrue(queueOut.isDurable()); assertFalse(queueOut.isExclusive()); assertFalse(queueOut.isAutoDelete()); @@ -211,12 +221,17 @@ public class RabbitManagementTemplateTests { public void testDeleteExchange() { String exchangeName = "testExchange"; Exchange testExchange = new DirectExchange(exchangeName); - this.template.addExchange(testExchange); - Exchange exchangeToAssert = this.template.getExchange(exchangeName); + ExchangeInfo info = new ExchangeInfo(); + info.setArguments(testExchange.getArguments()); + info.setAutoDelete(testExchange.isAutoDelete()); + info.setDurable(testExchange.isDurable()); + info.setType(testExchange.getType()); + this.rabbitRestClient.declareExchange("/", testExchange.getName(), info); + ExchangeInfo exchangeToAssert = this.rabbitRestClient.getExchange("/", exchangeName); assertEquals(testExchange.getName(), exchangeToAssert.getName()); assertEquals(testExchange.getType(), exchangeToAssert.getType()); - this.template.deleteExchange(testExchange); - assertNull(this.template.getExchange(exchangeName)); + this.rabbitRestClient.deleteExchange("/", testExchange.getName()); + assertNull(this.rabbitRestClient.getExchange("/", exchangeName)); } } diff --git a/src/reference/asciidoc/amqp.adoc b/src/reference/asciidoc/amqp.adoc index f7e22890..3df25f0e 100644 --- a/src/reference/asciidoc/amqp.adoc +++ b/src/reference/asciidoc/amqp.adoc @@ -4160,66 +4160,18 @@ To check if a message was delayed, use the `getReceivedDelay()` method on the `M It is a separate property to avoid unintended propagation to an output message generated from an input message. -[[management-template]] +[[management-rest-api]] ==== RabbitMQ REST API When the management plugin is enabled, the RabbitMQ server exposes a REST API to monitor and configure the broker. A https://github.com/rabbitmq/hop[Java Binding for the API] is now provided. -In general, you can use that API directly, but a convenience wrapper is provided to use the familiar Spring AMQP `Queue`, `Exchange`, and `Binding` domain objects with the API. -Much more information is available for these objects when using the `com.rabbitmq.http.client.Client` API directly -(`QueueInfo`, `ExchangeInfo`, and `BindingInfo` respectively). -The following operations are available on the `RabbitManagementTemplate`: +The `com.rabbitmq.http.client.Client` is a standard, immediate and, therefore, blocking API. +It is based on the https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#spring-web[Spring Web] module and its `RestTemplate` implementation. +On the other hand, the `com.rabbitmq.http.client.ReactorNettyClient` is a reactive, non-blocking implementation based on the http://projectreactor.io/docs/netty/release/reference/docs/index.html[Reactor Netty] project. -[source, java] ----- -public interface AmqpManagementOperations { +The hop dependency (`com.rabbitmq:http-client`) is now also `optional`. - void addExchange(Exchange exchange); - - void addExchange(String vhost, Exchange exchange); - - void purgeQueue(Queue queue); - - void purgeQueue(String vhost, Queue queue); - - void deleteQueue(Queue queue); - - void deleteQueue(String vhost, Queue queue); - - Queue getQueue(String name); - - Queue getQueue(String vhost, String name); - - List getQueues(); - - List getQueues(String vhost); - - void addQueue(Queue queue); - - void addQueue(String vhost, Queue queue); - - void deleteExchange(Exchange exchange); - - void deleteExchange(String vhost, Exchange exchange); - - Exchange getExchange(String name); - - Exchange getExchange(String vhost, String name); - - List getExchanges(); - - List getExchanges(String vhost); - - List getBindings(); - - List getBindings(String vhost); - - List getBindingsForExchange(String vhost, String exchange); - -} ----- - -Refer to the javadocs for more information. +Refer to their javadocs for more information. [[exception-handling]] ==== Exception Handling diff --git a/src/reference/asciidoc/appendix.adoc b/src/reference/asciidoc/appendix.adoc index 0edab871..82debf89 100644 --- a/src/reference/asciidoc/appendix.adoc +++ b/src/reference/asciidoc/appendix.adoc @@ -570,9 +570,8 @@ See <> for more information. ===== The RabbitManagementTemplate -The `RabbitManagementTemplate` has been introduced to monitor and configure the RabbitMQ Broker using the REST API -provided by its https://www.rabbitmq.com/management.html[Management Plugin]. -See <> for more information. +The `RabbitManagementTemplate` has been introduced to monitor and configure the RabbitMQ Broker using the REST API provided by its https://www.rabbitmq.com/management.html[Management Plugin]. +See <> for more information. ===== Listener Container Bean Names (XML) diff --git a/src/reference/asciidoc/whats-new.adoc b/src/reference/asciidoc/whats-new.adoc index 77eeac4d..9b02381c 100644 --- a/src/reference/asciidoc/whats-new.adoc +++ b/src/reference/asciidoc/whats-new.adoc @@ -19,13 +19,11 @@ RabbitMQ `ConnectionFactory` instances created by the `RabbitConnectionFactoryBe Certain classes have moved to different packages; most are internal classes and won't affect user applications. Two exceptions are `ChannelAwareMessageListener` and `RabbitListenerErrorHandler`; these interfaces are now in `org.springframework.amqp.rabbit.listener.api`. - ===== Publisher Confirms Changes Channels enabled for publisher confirms are not returned to the cache while there are outstanding confirms. See <> for more information. - ===== Listener Container Factory Improvements The listener container factories can now be used to create any listener container, not just those for use with `@RabbitListener` s or the `@RabbitListenerEndpointRegistry`. @@ -35,7 +33,7 @@ See <> for more information. ===== Broker Event Listener -A `BrokerEventListener` is introduced to publish selected broker events as `ApplictionEvent` s. +A `BrokerEventListener` is introduced to publish selected broker events as `ApplicationEvent` s. See <> for more information. ===== RabbitAdmin Changes @@ -50,5 +48,11 @@ The `RabbitTemplate` now can be configured with the `noLocalReplyConsumer` optio See <> for more information. ===== Message Converts + A new `Jackson2XmlMessageConverter` is introduced to support converting messages from/to XML format. -See <> for more information. \ No newline at end of file +See <> for more information. + +===== Management REST API + +The `RabbitManagementTemplate` is now deprecated in favor of the direct `com.rabbitmq.http.client.Client` (or `com.rabbitmq.http.client.ReactorNettyClient`) usage. +See <> for more information.